Autor Beitrag
Bääääär
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 117



BeitragVerfasst: Di 24.10.06 19:10 
Ich weiß, es nervt euch sicher alle, aber ich möchte alle Dateien eines Ordners kopieren, und zwar ohne API und mit Fortschrittsbalken. Ich habe mir dazu eine kleine Routine gebastelt, die aber irgendwie nich funtionieren will.

Variablen:

textlabel:Tlabel, darauf soll angezeigt werden, welche Datei grade kopiert wird.
progresslabel:TLabel, es soll den Fortschritt in Prozent anzeigen.
Progress:Tprogressbar, zeigt den Fortschritt an,
items:Tstrings, beinhaltet Ordner und Dateinamen, die kopiert werden sollen.
Topath:String, der Zielpfad.

Die Function findtopath soll den Zielpfad zum Kopieren herausfinden. Dazu wird der ursprungspfad genommen, und ein Teil davon abgezogen (nämlich genau den angegebenen Ordner in "items", z.B. "C:\ordner\"). Anschließend wird der Zielordner dazugefügt. Befand sich die Datei in "C:\ordner\ordner2\hallo.txt" und in "items" stand "C:\ordner\" und der Zielordner ist "C:\", dann soll die Datei in "C:\ordner2\hallo.txt" landen (ich hoffe, das war jetzt verständlich... ^^)

Die Function "VerzGroesse" soll die Größe aller Dateien im in "items" angegebenen Ordner herausfinden, damit zu begin die gesammt zu kopierende Menge an Daten herausgefunden werden kann (für den Fortschrittsbalken).

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
unit copyunit;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, XPMan, StdCtrls, Menus, appevnts,ShellApi, ComCtrls, inifiles, FileCtrl;

Function VerzGroesse(Verzeichnis:string):longint;
procedure startsave(items:TStrings; fileprogress,progress:Tprogressbar; textlabel,filelabel,progresslabel:TLabel; Topath:String); // wird aufgerufen, um den Kopiervorgang einzuleiten

var gefunden: TStrings;
    VerzListe:Tstringlist;
    groesse:longint;
    mem:Tmemorystream;

implementation

procedure GetFilesInDirectory(Directory: Stringconst Mask: String;
                              List: TStrings;
                              WithSubDirs, ClearList: Boolean);
procedure ScanDir(const Directory: String);
var
  SR: TSearchRec;
begin
  if FindFirst(Directory + Mask, faAnyFile - faDirectory, SR) = 0 then try
    repeat
      List.Add(Directory + SR.Name)
    until FindNext(SR) <> 0;
  finally
    FindClose(SR);
  end;

  if WithSubDirs then begin
    if FindFirst(Directory + '*.*', faAnyFile, SR) = 0 then try
      repeat
        if ((SR.attr and faDirectory) = faDirectory) and
           (SR.Name <> '.'and (SR.Name <> '..'then
          ScanDir(Directory + SR.Name + '\');
      until FindNext(SR) <> 0;
    finally
      FindClose(SR);
    end;
  end;
end;

begin
  List.BeginUpdate;
  try
    if ClearList then
      List.Clear;
    if Directory = '' then Exit;
    if Directory[Length(Directory)] <> '\' then
      Directory := Directory + '\';
    ScanDir(Directory);
  finally
    List.EndUpdate;
  end;
end;

Function VerzGroesse(Verzeichnis:string):longint;
Var SR: TSearchRec;
    Groesse: longint;
Begin
  Groesse:=0;
  If Verzeichnis[length(Verzeichnis)]<>'\' Then Verzeichnis:=Verzeichnis+'\';
  If FindFirst(Verzeichnis+'*.*',$3F,SR)=0 Then Begin
    inc(files);
    If ((SR.Attr and faDirectory)>0and (SR.Name<>'.'and (SR.Name<>'..'Then Begin
      Groesse:=Groesse+VerzGroesse(Verzeichnis+SR.Name)
    End Else Begin
      Groesse:=Groesse+SR.Size;
    End;
    If (SR.Name<>'.'and (SR.Name<>'..'Then VerzListe.Add(Verzeichnis+SR.Name);
    While FindNext(SR)=0 do Begin
      inc(files);
      If ((SR.Attr and faDirectory)>0and (SR.Name<>'.'and (SR.Name<>'..'Then Begin
        Groesse:=Groesse+VerzGroesse(Verzeichnis+SR.Name)
      End Else Begin
        Groesse:=Groesse+SR.Size;
      End;
      If (SR.Name<>'.'and (SR.Name<>'..'Then VerzListe.Add(Verzeichnis+SR.Name);
    End;
  End;
  FindClose(SR);
  Result:=Groesse;
End;


function GetFileSizeEx(const AFileName: String): Int64;
var
  F: TSearchRec;
begin
  Result := -1;
  if FindFirst(AFileName, faAnyFile, F) = 0 then
  begin
    try
      Result :=  F.FindData.nFileSizeLow or (F.FindData.nFileSizeHigh shl 32);
    finally
      SysUtils.FindClose(F);
    end;
  end;
end;

procedure copy(FromPath,ToPath:string);
begin
mem.LoadFromFile(frompath);
mem.SaveToFile(topath);
end;

function findtopath(todir,filename,entf:String):string;
var
i:integer;
s:string;
begin
for i:=0 to length(entf)-1 do
  begin
    s:=filename;
    s[1]:=char(#0);
  end;
result:=includetrailingbackslash(todir)+s;
end;

function givefile(filename:string):string;

var  laufwerk: char;
  verzeichnisse: string;
begin
  ProcessPath(filename, laufwerk, verzeichnisse, result);
end;


procedure startsave(items:TStrings; fileprogress,progress:Tprogressbar; textlabel,filelabel,progresslabel:TLabel; Topath:String);
var
i,j, copiedfiles:longint;
s:string;
begin

textlabel.Caption:='System Save bereitet den Kopiervorgang vor ...';

//Datenmenge berechnen
groesse:=0;
if items.count>100 then
  begin
    showmessage('Es dürfen nicht mehr als 100 Verzeichnisse und Dateien angegeben werden!');
    exit;
  end;
for i:=0 to items.Count-1 do
  begin
    s:=items[i];
    if s[length(s[i])]<>'\' then
      begin
        try
          groesse:=groesse+getfilesizeex(s);
        finally
        end;
      end
    else
    groesse:=groesse+verzgroesse(items[i]);
  end;

//initialisation
fileprogress.Min:=0;
progress.Min:=0;
fileprogress.max:=100;
progress.Max:=100;
fileprogress.Position:=0;
progress.position:=0;
textlabel.Caption:='Bereitet den Kopiervorgang vor ...';
mem:=tMemorystream.Create;
copiedfiles:=0;

//copying
for j:=0 to items.Count-1 do
  begin
    if extractfileext(items[j])='' then //wenn ein Ordner in "items[j]" steht, dann ...
      begin
        GetFilesInDirectory(items[j], '*.*',gefunden, true, true); //Liste aller zu kopierenden Dateien ermitteln
        for i:=0 to gefunden.Count-1 do //hier kommt der Fehler
          begin
            if (extractfileext(gefunden[i])<>'')and (fileexists(gefunden[i])) then /wenn die Datei wirklich eine Datei ist, und auch existiert, dann ...
              begin
                inc(copiedfiles,getfilesizeex(gefunden[i])); //bereits kopierte Datenmenge berechnen
                progresslabel.caption:=inttostr((copiedfiles div groesse)*100)+'%'//Prozentwert ausrechnen
                textlabel.caption:=gefunden[i]+findtopath(topath,gefunden[i],items[j]); // Datei anzeigen
                if fileexists(gefunden[i]) then copy(gefunden[i],findtopath(topath,gefunden[i],items[j])); //Datei kopieren
              end;
          end;
      end
    else //wenn in "itens[j]" kein Ordner, sondern eine Datei steht, dann ...
      inc(copiedfiles,getfilesizeex(items[j]));  //bereits kopierte Datenmenge berechnen
      progresslabel.caption:=inttostr((copiedfiles div groesse)*100)+'%'//Prozentwert ausrechnen
      textlabel.caption:=gefunden[i]+findtopath(topath,gefunden[i],items[j]); //Datei anzeigen
      if fileexists(items[j]) then copy(items[j],findtopath(topath,items[j],givefile(items[j]))); //Datei kopieren
  end;

//desinit
mem.Free;


end;

end.


So, ich hoffe, das war verständlich...

Danke schon mal für die Mühe, das alles durchzulesen, und in erwartung auf eure Antworten

The Bääääär
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19312
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 24.10.06 20:08 
Warum denn nicht einfach mit der API??? Ich meine, das heißt doch nicht, dass der Windows Kopierdialog angezeigt werden muss!

Jedenfalls dürfte deine eine der langsamsten und speicheríntensivsten Lösungen sein, die mir zu dem Thema einfallen würden...

Jedenfalls: Wie Luckie :wink: und ein paar andere im Forum (mich eingeschlossen) immer wieder bräuchte ich jetzt dringend eine Glaskugel... :twisted:
WAS funktioniert denn nicht??? :roll:
Steht da, wenn du das Programm startest da
user profile iconBääääär hat folgendes geschrieben:
irgendwie nich funtionieren will.

als Fehlermeldung oder was passiert sonst?
Und wie stehts mit Debugging? Wird die Dateiliste nicht korrekt gefunden, nicht korrekt abgearbeitet, oder was?

//EDIT: Ich überfliege den Code trotzdem mal, aber ob ich da was sehe, wenn ich nicht weiß, was nicht geht, naja, mal sehen...
Bääääär Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 117



BeitragVerfasst: Di 24.10.06 23:35 
Sorry!

Er meint, es wäre eine Zugriffsverletzung. Aber die Funktion für die Liste der Dateien (Name: "gefunden") funzt, das habe ich in einem Extra-Programm getestet. Alle Funktionen laufen einzeln, aber zusammen woll'n sie nich. Wie gesagt, Zugriffsverletzung...

Danke trotzdem,
The Bääääär
Lannes
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2352
Erhaltene Danke: 4

Win XP, 95, 3.11, IE6
D3 Prof, D4 Standard, D2005 PE, TurboDelphi, Lazarus, D2010
BeitragVerfasst: Di 24.10.06 23:49 
Hallo,

abgesehen davon das man TStrings nicht direkt verwenden sollte,
fehlen TStrings.Create bzw. TStringList.Create in deinem Code.

_________________
MfG Lannes
(Nichts ist nicht Nichts) and ('' <> nil ) and (Pointer('') = nil ) and (@('') <> nil )
AXMD
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 4006
Erhaltene Danke: 7

Windows 10 64 bit
C# (Visual Studio 2019 Express)
BeitragVerfasst: Mi 25.10.06 00:18 
@Bäääääär: du willst keine API-Funktionen verwenden? Was meinst du was FindFirst, FindNext etc. sind? Gekapselte API-Funktionen... ;)

AXMD
C.Schoch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 28

WinXp
Turbo Dephi Win 32
BeitragVerfasst: Mi 25.10.06 00:18 
Hi,
Wohl dem der viel Arbeitsspeicher hat! :shock:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
procedure copy(FromPath,ToPath:string);
begin
mem.LoadFromFile(frompath);
mem.SaveToFile(topath);
end;


Läuft das ganze in einem Thread? wenn Ja wie übergiebst du die Variablen?
Kann es sein, dass die Dateien gesperrt sind die Du kopieren möchtests.

_________________
Das System hofft auf Besserung
[Siemens]
Bääääär Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 117



BeitragVerfasst: Mi 25.10.06 23:27 
Hey, nehmt's mir nicht übel! Ich wollte einfach mal selber soein Programm schreiben. Ok, mit dem "Ohne API" meinte ich, dass man mir nicht wieder diesen Anderen Vorschlag vorschreiben soll, auf den hier so oft verwiesen wird (weiß grade nicht, wie der hieß, egal)

@C.Schoch: Nee, es läuft nich in 'nem Thread, warum?
@AXMD: Mmhh. Das wusste ich nicht...
@alle: Klar, meine Variante ist vielleicht nicht die beste und sicher nicht die "speicherunintensivste" aber darum ging es mir auch gar nicht.

So, ich habe jetzt
ausblenden Delphi-Quelltext
1:
2:
3:
4:
gefunden:=TStrings.create;
...
...
gefunden.free;
hinzugefügt. Jetzt kommt an der gleichen Stelle, wo vorher der Fehler war, ein neuer Fehler 'Abstakter Fehler'. Für mich nicht sehr aussagekräfitg. Kann mir da vielleicht jemand helfen?
AXMD
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 4006
Erhaltene Danke: 7

Windows 10 64 bit
C# (Visual Studio 2019 Express)
BeitragVerfasst: Mi 25.10.06 23:33 
TStrings ist abstrakt. Von einer abstrakten Klasse kannst du keine Instanz erstellen. Nimm eine der Kindklassen (z.B. TStringList)

AXMD
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19312
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 25.10.06 23:34 
Tja, weil du TStrings.Create statt TStringList.Create benutzt.

In TStrings sind einige Sachen nur definert "wie die Funktionen aussehen" aber nicht implementiert bzw. die ganze Klasse ist nur definiert aber beinhaltet keinen Code dazu. Der entsprechende Code wird dann erst in einer davon abgeleiteten Klasse geschrieben.
So kannst du dann, egal um welche abgeleitete Klasse es sich handelt, sagen: Rufe die Funktion xy auf, die in der Oberklasse definiert wurde. Wie diese dann in der abgeleiteten Klasse implemetiert ist, ist dann egal.
Bääääär Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 117



BeitragVerfasst: Do 26.10.06 00:38 
Ah, so ist das also! ^^ Ok, jetzt geht's, leider läuft die Sache mit dem Findtopath noch nicht so ganz. Naja, das werde ich auch noch schaffen. Danke jaenicke!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19312
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 26.10.06 00:52 
Naja, dazu noch ein Tipp: Mit Delete löschst du was aus einem String. Und wenn du jetzt "c:\ordner" aus "c:\ordner\xyz" löschen willst, dann schreib einfach Delete('c:\ordner\xyz', 1, Length('c:\ordner')). Dann werden am Anfang so viele Zeichen gelöscht wie der zweite String welche hat. Im Beispiel würde also "\xyz" bei herauskommen. (Es geht allerdings nicht genauso, denn Delete muss als ersten Parameter eine echte Variable bekommen, aber das soll ja auch nur ein Beispiel zur Veranschaulichung sein...
Bääääär Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 117



BeitragVerfasst: Do 26.10.06 01:28 
Danke, aber ich hab's jetzt anders gelöst. Der Zielpfad ergibt sich aus dem Topath + den ursprungsname der Datei ohne Laufwerk. Also Aus C:\zielordner\ und C:\ursprungsordner\datei.dat wird C:\zielordner\ursprungsordner\datei.dat.

Und ich habe noch ein Forcedirectories vor doe Kopieren-Zeile gesetzt. ^^ das war nämlich schon wieder der nächste Fehler ('das Verzeichnis existiert nicht ...'). ^^

Aber nun geht das kopieren! Nur der Fortschrittsbalken will noch nicht so ganz. Ich habe festgestellt, dass irgendwas mit dem Zusammenrechnen der Gesammtdatenmenge nicht stimmt. die Menge der kopierten Daten ist nämlch zum schull größer als die geesammten Daten...
Bääääär Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 117



BeitragVerfasst: Do 26.10.06 08:56 
So, der Fehler beim berechnen der Datenmenge ist behoben:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
//Datenmenge berechnen
groesse:=0;
if items.count>100 then
  begin
    showmessage('Es dürfen nicht mehr als 100 Verzeichnisse und Dateien angegeben werden!');
    exit;
  end;
for i:=0 to items.Count-1 do
  begin
    s:=items[i];
    if s[length(s)]<>'\' then //hier stand s[length(s[i])] - klar, dass das nicht gehen kann...
      begin
        try
          groesse:=groesse+GetFileSizeEx(s);
        finally
        end;
      end
    else
    groesse:=groesse+verzgroesse(s);
  end;
application.ProcessMessages;


Auch beim Errechnen des Fortschritts gibt's noch Probleme. copiedfiles ist zum schluss exakt gleich Groesse, aber der Fortschrittsbalken, der bei mir jetzt durch progress.Position:=round((copiedfiles/groesse)*100); berechnet wird fängt irgendwie bei 50% an, endet jedoch am Ende genau bei 100%. So progress.Position:=(round((copiedfiles/groesse)*100)-50)*2; klappts dann einwandfrei. Jedoch scheint mir die Rechnung etwas absurd...

Dann noch eine Frage: Wie kann man soetwas denn beschleunigen, weil ihr ja alle meintet, meine Variante wäre extrem langsam.

The bääääär
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Do 26.10.06 09:09 
In dem du API-Funktionen benutzt. Entweder CopyFile oder CopyFileEx, wenn du einen Kopierfortschritt haben willst. Desweiteren lässt sich bei SHFileOperation auch der Dialog unterdrücken.

BTW ohne API-Funktionen wird es nie gehen, wie soll sich denn dein Programm mit Windows verständigne, wenn nicht über die WinAPI? Selbst hinter den Stream stehen nur API-Funktionen.
Bääääär Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 117



BeitragVerfasst: Do 26.10.06 09:17 
Ok, wie gesagt, ich meinte dieses FileShareOperation. Kannst du mir sage, wie ich mit diesem CopyFileEx umzugehen habe?
Du meinst ich soll es einfach anstelle meiner memorystream-kopier-procedure einsetzen?
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Do 26.10.06 09:19 
Eine Suche mit Google oder im Forum hätte es auch getan:
www.michael-puff.de/...iges/CopyFileEx.html

Warum nimmst du die überhaupt? Und was soll das, dass du keine API-Funktionen nehmen willst?
Bääääär Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 117



BeitragVerfasst: Do 26.10.06 09:24 
Weil überall, wo man fragt auf dieses SHFileOperation hingewiesen wird. Ich will aber nicht, dass dieses dämliche Fenster erscheint und ich will auch nicht, dass bei einer beschädigten Datei gleich der gane kopiervorgang abgebrochen wird. Das war ja für mich der einzige grund, das ganze selber zu schreiben.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19312
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 26.10.06 09:51 
Was für ein dämliches Fenster? Die GUI ist doch nur optional, wenn du SHFileOperation benutzt! Ich behaupte mal, du hast dir die Funktion noch nie angesehen. Du kannst da natürlich angeben, ob Fehler angezeigt werden sollen, ob Bestätigungen vom User eingeholt werden sollen, ob eine Fortschirttsanzeige kommen soll oder nicht, etc.
Sieh dir die Funktion doch erstmal an, bevor du sagst: "Nutze ich nicht" :roll:
msdn.microsoft.com/l...s/shfileopstruct.asp

Was die Fehlertoleranz angeht: Da hab ich im Moment keine Ahnung, was bei einem Fehler passiert, wenn die Fehleranzeige abgeschaltet ist. Ich nehme an, der bricht trotzdem ab?
Aber da kann dir user profile iconLuckie vermutlich mehr zu sagen.
Bääääär Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 117



BeitragVerfasst: Do 26.10.06 17:05 
Natürlich habe ich sie mir angeschaut, warum sonst sagen alle, an soll diese Function verwenden. Aber ich verstehe das ganze Ding nicht, ich weiß nicht, wie ich das verwenden kann. Und für mich sah das so aus, als könnte man den Fortschritt nur mit diesem Info-Fenster von Win anzeigen. Und das wollte ich nicht.
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1335
Erhaltene Danke: 118

Win 10
RIO, CE, Lazarus
BeitragVerfasst: Do 26.10.06 18:28 
mal eine ganz andere richtung:

ich habe mir schon ettliche male richtig fehlerresistente kopierroutinen gebastelt. und zwar nicht mit direkten win API aufrufen.
sondern mit dem delphi kapselungen AssignFile, Reset, ReWrite, BlockRead, BlockWrite und CloseFile. über die FileMode variable kamm man auch schön bestimmen wie man die dateien auf machen will.
Ich habe damit immer sehr gute erfahrungen gemacht. braucht wenig speichern und ist ordentlich schnell wenn man eine angemessende puffergröße verwendet.

_________________
Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?