Hallo,
Also mit meinem Programm soll man einen Ordner mit Unterordnern auf einem Netzwerkspeicher abspeichern können.
Ich möchte das ganze mit einem Stream realisieren da das soweit ich bis jetzt in Erfahrung bringen konnte nur mit einem Stream geht.
Falls es auch anders geht könnt ihr mir auch gerne alternativen nennen (wenn möglich auch mit Beispielen).
Aktueller Stand ist die Funktion Copy Dir und Copy (Copy verwende ich um einzelne Dateien zu kopieren und die funktioniert so auch komplett):
P.S.: Die Funktionen werden in einem Backgroundworker aufgerufen der so aufgebaut ist:
Backgroundworker:
void worker_DoWork(object sender, DoWorkEventArgs e)
{
if (Datei == true)
{
DirectoryInfo dirinfo = new DirectoryInfo(pfad.Substring(0, pfad.Length - openFileDialog1.SafeFileName.Length));
Stream inStream = File.Open(pfad, FileMode.Open);
Stream outStream = File.Create(@"NETZWERKPFAD" + comboboxselecteditem + "\\" + openFileDialog1.SafeFileName);
int prozentfertig = (int)e.Argument;
while (prozentfertig < 100)
{
prozentfertig++;
Copy(inStream, outStream);
worker.ReportProgress(prozentfertig);
Thread.Sleep(50);
}
inStream.Close();
inStream.Dispose();
outStream.Close();
outStream.Dispose();
dateien.Add(pfad);
e.Result = prozentfertig;
}
else
{
DirectoryInfo di = new DirectoryInfo(pfad);
CopyDir(pfad, @"NETZWERKPFAD" + comboboxselecteditem + "\\" + di.Name + "\\");
}
}
Worker Progress Changed:
void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
Copy:
public void Copy(Stream input, Stream output)
{
byte[] buffer = new byte[32 * 1024];
int bytesRead;
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) != 0)
{
output.Write(buffer, 0, bytesRead);
}
}
Meine Frage an euch wäre jetzt wie ich die Übertragung von Ordner schreiben kann.
Ich hatte bis jetzt versucht es mit der Copy Funktion hinzu bekommen indem ich das Verzeichnis Rekursive durchsuchen lasse und dann in einer foreach-Schleife die Copy Funktion verwende.
Das funktioniert soweit auch ganz gut nur das die Progressbar sich nicht aktualisiert (Die Progressbar wurde Invoked).
Hoffentlich könnt ihr mir helfen
MfG Scarpall
Die while Schleife sieht seltsam aus. Du kopierst da immer das gleiche, so lange bis prozentfertig == 100?
Ja das erschien mir auchseltsam
Aber es funktioniert und sah für mich nicht so aus als ob etwas überschrieben werden würde
MfG scarpall
Hi!
Das funktioniert soweit auch ganz gut nur das die Progressbar sich nicht aktualisiert (Die Progressbar wurde Invoked).
Siehe hier:
Backgroundworker
Hast du bspw. das Property WorkerSupportsCancellation auf true gesetzt?
Gruss,
DaMoe
Edit: Ich meinte natuerlich WorkerReportsProgress und nicht WorkerSupportsCancellation.
Wie Du Deine Progress-Anzeige für Deine Ordner-Kopieren-Methode erstellst ist im Prinzip Deine Sache; das machen die meisten Anwendungen jedes mal anders. Einige zeigen auch nur das Kopieren von Dateien an.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
@scarpall
Ganz einfach wäre es auch mit File.Copy gegangen.
Das kopiert auch über Netzwerkfreigaben.
Dann musst du dich nicht mit dem ganzen Bytes/Stream rumschlagen.
Ansonsten sagt Abt soweit alles was du noch optimieren solltest.
T-Virus
Developer, Developer, Developer, Developer....
99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.
Er will aber ein Progress und das geht bei File.Copy nicht Byte-weise, sondern nur nach Anzahl der Dateien.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Ich kopiere die Dateien auch blockweise, da ich dann :
Die Geschwindigkeit vom File.Copy ist identisch zum blockweise Kopieren.
Hier noch eine Anmerkung zum Windows File-Copy-Dialog:
The author of the Windows file copy dialogue visits some friends
Grüße Bernd
Workshop : Datenbanken mit ADO.NET
Xamarin Mobile App : Finderwille Einsatz App
Unternehmenssoftware : Quasar-3
Hallo
schon mal ein herzliches Dankeschön an alle die hier geantwortet haben.
Ich habe nochmal einiges bearbeitet so das dies der aktuelle Stand ist.
CopyDir:
DirectoryInfo dirinfo = new DirectoryInfo(pfad);
if (!Directory.Exists(ziel))
Directory.CreateDirectory(ziel);
foreach (FileInfo fi in dirinfo.GetFiles())
{
CopyFile(dirinfo.FullName + "\\" + fi.Name, ziel + "\\" + fi.Name);
}
foreach (DirectoryInfo di in dirinfo.GetDirectories())
{
CreateFolders(di.FullName, ziel + "\\" + di.Name);
}
CopyFile:
int bytesRead = 0;
int bytesPerChunk = 1000001;
using (FileStream fs = new FileStream(source, FileMode.Open, FileAccess.Read))
{
progressBar1.Parent.Invoke(new MethodInvoker(delegate { progressBar1.Maximum = (int)fs.Length; }));
using (BinaryReader br = new BinaryReader(fs))
{
using (FileStream fsDest = new FileStream(destination, FileMode.Create))
{
BinaryWriter bw = new BinaryWriter(fsDest);
byte[] buffer;
for (int i = 0; i < fs.Length; i += bytesPerChunk)
{
while(bytesPerChunk > (fs.Length - i))
{
bytesPerChunk -= 10;
}
buffer = br.ReadBytes(bytesPerChunk);
bw.Write(buffer);
bytesRead += bytesPerChunk;
worker.ReportProgress(bytesRead, fs.Length);
}
}
}
}
Nun funktioniert die Progressbar auch.
Einziges Problem ist das ich beim Kopieren von größeren Dateien den Fehler bekomme das der Wert zu groß für Progressbar.Maximum ist.
Mir ist auch klar das es sich bei diesem Wert um einen Integer handelt und dieser zum Beispiel nicht die Bytes einer z.B. 2 GB grpßen Imagedatei speichern kann.
Ich weiß im moment nur nicht wie ich den Code umändern muss so das:
@Abt:
- Wenn Du den Stream nur nutzt, damit Du einen Progress hin bekommst, nimm besser die Win32 API und CopyFileEx. Das kann Dir genauso den Progress anzeigen arbeitet aber schneller und zuverlässiger.
Danke für den Tipp ich schaue es mir momentan an arbeite aber noch nicht damit weil ich vorher noch nie mit einer API gearbeitet habe.
- Was soll das Sleep?
Hatte ich nur eingefügt weil das in einem MSDN Beispiel auch drin war.
- Dein While sollte immer die Rest-Bytes prüfen, nicht den Prozent-Satz. Sehr fehleranfällig. Dass Du den Zustand des übertragenen extern speicherst (bytesRead) kann nach hinten los gehen. Code wirklich an dieser sehr wichtigen Stelle deutlich lesbarer und wartbarer machen. Das ganze Ding ist auch so nicht testbar! Und sowas MUSS testbar sein.
Auch diesen Tipp habe ich dankend übernommen.
5 Verwende usings und lade so viel wie möglich in dem RAM vor.
die usings habe ich nun verwendet. Wie genau meinst du das mit viel in den RAM vorladen bzw. wie kann ich das denn machen?
- öffne Dateien in so einem Fall immer Shared und nicht exklusiv. Ansonsten sind große Dateien eewwwig geblockt.
Wie kann ich das denn Shared öffnen?
Sorry für solche Fragen ich bin kein gelernter Programmieren hatte nur damals in der Ausbildungszeit 2 oder 3 Programmierlehrgänge und hatte festgestellt das es mir Spaß macht.
Den Rest hatte ich mir dann selber beigebracht.
- Gerade bei Windows Shares sollte man Dein Vorhaben eher vermeiden oder zumindest deutlich optimierter arbeiten (größere Byte Pakete, um SMB Overhead zu vermeiden).
die Byte Pakete habe ich vergrößert (auf 1000001 weil ich ja später die Pakete je nach restbytes um 10 reduziere so bleibt ja mindestens 1 byte am Ende übrig)
Edit:
Ich habe mir gerade ein Beispielprojekt für CopyFileEx runtergeladen.
Da sieht das button click event einfach so aus:
CopyFileEx(sourceFile, destFile, new CopyProgressRoutine(this.CopyProgressHandler), IntPtr.Zero, ref pbCancel, CopyFileFlags.COPY_FILE_RESTARTABLE);
Was müsste ich denn da umändern um es mit einer Progressbar verwenden zu können ?
Bzw. wie kann ich da die Übertragenen bytes etc auslesen ?
MfG Scarpall
Wie genau meinst du das mit viel in den RAM vorladen bzw. wie kann ich das denn machen?
Ich habs selbst aus Interesse getestet: bringt übers lokale Netz nichts(/nicht viel).
Wie kann ich das denn Shared öffnen? File.Open-Methode (String, FileMode, FileAccess, FileShare) -> FileShare.
Ich habe mir gerade ein Beispielprojekt für CopyFileEx runtergeladen.
Da sieht das button click event einfach so aus:CopyFileEx(sourceFile, destFile, new CopyProgressRoutine(this.CopyProgressHandler), IntPtr.Zero, ref pbCancel, CopyFileFlags.COPY_FILE_RESTARTABLE);
Was müsste ich denn da umändern um es mit einer Progressbar verwenden zu können ?
Das ist nichts zum Ändern. Das ist die Win32 API Aufruf, die die Anwendung ansprechen muss. Arg toll ist dieses Beispiel aber nicht.
Ich habe gestern Abend diese Funktion noch in meine Lib integriert, die ich in Performant von vielen Dateien die Größe bestimmen angekündigt habe.
Im Lauf des Februars veröffentliche ich es dann kann man sehen, dass das gaaar nich so schwer ist. Brauchst eben einen Callback, der die Status-Benachrichtigungen entgegen nimmt.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code