Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - [Delphi] FilenameToFile und Andersrum


IhopeonlyReader - Fr 06.09.13 16:41
Titel: [Delphi] FilenameToFile und Andersrum
Guten Tag,
nachdem ich mein Verschlüsselungsprogramm geschrieben hatte, dachte ich mir, dass die Dateitypen oder namen sicherlich schon einiges über den Inhalt aussagen und ich diese deshalb ebenfalls "verschlüsseln" sollte.
Ich dachte einfach daran, den Dateinamen mit in die exe zu schreiben und einfach Datei für Datei zu "zählen" ( z.B. in "0" umzubennen), da die Filename Möglichkeiten sehr eingeschränkt sind.

Doch scheinbar selbst bei einem solch einfachen Problem verzweifel ich schon, ich habe meinen Quelltext "angeschaut" und dachte, theoretisch müsste es funktionieren. Evtl benutzte ich auch einfach nur falsche Rechte beim Filestream (gibt's irgendwo ne übersicht, wann man share oder normale etc. verwenden sollte?)

Hier mal meine Schreibmethode

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:
procedure NameToFile( Path: String; i: integer = -1);
var Dir, FileName, NFL: String//NFL = NewFile
    FPL: Word; //FilePathLength
    FS: TFileStream;
begin
if not FileExists( Path ) then exit;
Dir := ExtractFilePath(Path);
FPL := length( Dir );
FileName := Copy( Path, FPL+1, length(Path)-FPL );
NFL := IntToStr( i );
while FileExists( Dir + NFL ) do
  begin
  inc( i );
  NFL := IntToStr( i );
  end;   
RenameFile( Path, NFL );
FS := TFileStream.Create( Dir + NFL, fmOpenReadWrite or fmShareDenyRead or fmShareDenyWrite );
  try
    FPL := length( Filename );
    FS.Size := FS.Size + FPL + 2//hatte ich vorher weggelassen
    FS.Seek( -FPL-2, soFromEnd ); //hier dann entsprechend: FS.Seek( 0, soFromEnd );
    FS.WriteBuffer( Pointer(FileName)^, FPL ); 
    FS.Seek( -2, soFromEnd ); //hier dann entsprechend: FS.Seek( 0,soFromEnd ); bzw. weggelassen
    FS.WriteBuffer( FPL, 2 ); // Länge des Strings ans Ende schreiben, damit dieser immer zu "finden" ist.
  finally
    FS.Free;
  end;
end;


Meine lese procedure

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
procedure LoadNameFromFile( Path: String );
var FileName: String;
    FPL: Word;
    FS: TFileStream;
begin
if not FileExists( Path ) then exit;

FS := TFileStream.Create( Path, fmOpenReadWrite or fmShareDenyRead or fmShareDenyWrite );
  try
    FS.Seek( -2, soFromEnd );
    FS.Read( FPL, 2 );
    FS.Seek( -FPL-2, soFromEnd );
    FS.Read( Pointer(FileName)^, FPL );
    FS.Size := FS.Size - FPL -2;
  finally
    FS.Free;
  end;
RenameFile( Path, FileName );
end;


warum klappt es nicht, sind die Rechte falsch? Hab ich etwas grundlegendes falsch gemacht, oder was ist falsch?
Das Umbennen klappt, aber das schreiben in die Datei und das laden aus der Datei nicht !, evt würde das laden klappen wenn das schreiben klappt..


Sinspin - Sa 07.09.13 07:49

Hi, lauf deine procedure NameToFile einfach mal im Einzelschritt durch und schau Dir an was in den Variablen zur Laufzeit steht. Ich denke Du kommst dann selber auf deinen Fehler.


IhopeonlyReader - Sa 07.09.13 13:26

vielen Dank, dass ich einer meldet :)

user profile iconSinspin hat folgendes geschrieben Zum zitierten Posting springen:
Hi, lauf deine procedure NameToFile einfach mal im Einzelschritt durch und schau Dir an was in den Variablen zur Laufzeit steht. Ich denke Du kommst dann selber auf deinen Fehler.

Und ich habe nun geschaut was darin steht, aber das ist alles so wie es soll !
Die Datei wird auch so umbenannt wie sie soll, aber der Dateiname (Filename) wird nicht in die Datei geschrieben. oder die lese Funktion funktioniert nicht.

Wenn du den Fehler so offensichtlich findest, dann schreib mir bitte eine Zeile wo deiner Meinung nach eine Variable "falsch" sein könnte.. ich selbst finde den fehler nicht :(

Edit: Beim schreiben gibt es keine fehler, aber die Datei wird nicht "größer".
Beim Lesen kommt die Meldung "Stream lesefehler"


Gerd Kayser - Sa 07.09.13 16:46

user profile iconIhopeonlyReader hat folgendes geschrieben Zum zitierten Posting springen:
Die Datei wird auch so umbenannt wie sie soll, aber der Dateiname (Filename) wird nicht in die Datei geschrieben. oder die lese Funktion funktioniert nicht.

Versuche es mal so:

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:
procedure TMainform.Button1Click(Sender: TObject);
var
  DateiNameAlt : String;
  DateiNameNeu : String;
  Laenge       : Int64;
  FS           : TFileStream;
begin
  DateiNameAlt :=  'f:\test.txt';
  DateiNameNeu := 'f:\0.';
  RenameFile(DateiNameAlt, DateiNameNeu);

  Laenge := Length(DateiNameAlt) * SizeOf(DateiNameAlt[1]);

  FS := TFileStream.Create(DateiNameNeu, fmOpenReadWrite or fmShareDenyRead or fmShareDenyWrite );
  try
    FS.Position := FS.Size;
    FS.Write(DateiNameAlt[1], Laenge);
    FS.Write(Laenge, SizeOf(Laenge));
  finally
    FS.Free;
  end;
end;

procedure TMainform.Button2Click(Sender: TObject);
var
  DateiNameAlt : String;
  DateiNameNeu : String;
  Laenge       : Int64;
  FS           : TFileStream;
  Gelesen      : Integer;
begin
  DateiNameAlt := 'f:\0';
  FS := TFileStream.Create(DateiNameAlt, fmOpenReadWrite or fmShareDenyRead or fmShareDenyWrite );
  try
    FS.Position := FS.Size - SizeOf(Laenge);
    FS.Read(Laenge, SizeOf(Laenge));
    FS.Position := FS.Position - SizeOf(Laenge) - Laenge;
    SetLength(DateiNameNeu, Laenge);
    FS.Read(DateiNameNeu[1], Laenge);
    FS.Size := FS.Size - SizeOf(Laenge) - Laenge;  // Infos aus Datei löschen.
  finally
    FS.Free;
  end;
  RenameFile(DateiNameAlt, DateiNameNeu);
end;

Die ganzen Fehlerprüfungen usw. einzubauen überlasse ich Dir.


IhopeonlyReader - So 08.09.13 12:54

Vielen Dank Gerd Kayser,
deine proceduren klappen fast.
in Button1Click (schreibmethode) darf DateinameNeu aber kein Pfad sein ! Edit: Es muss scheinbar schon ein Pfad sein :O
also Renamefile( path, extractfilepath(path)+newfilename)

ich habe es so abgeändert, dass die ersten 3 Zeilen so aussehen:

Delphi-Quelltext
1:
2:
3:
4:
if not OD.Execute then exit;
  DateiNameAlt :=  OD.Filename;;
  DateiNameNeu := Edit1.Text;
//dann wie bei dir weiter

dann klappt alles wunderbar :)

OD =OpenDialog...
Im Edit stand z.B. "0" drin. also eine einfache Ziffer. Die Umbenennung fand statt ! komischerweise wude auch der filestream erzeugt, aber wieso funktioniert

Delphi-Quelltext
1:
FS := TFileStream.Create( '0', fmOpenReadWrite or fmShareDenyRead or fmShareDenyWrite );                    

es ist ja kein Pfad am anfang angegeben.

Weitere Änderungen sind bei dir, dass du nicht Seek sondern Position := verwendest und anstatt Pointer(String)^ verwendest du String[1]
daraufhin lies ich mir mal diese beiden Speicheraddressen vergleichen:

Delphi-Quelltext
1:
Showmessage( IntToStr(  Cardinal(@DateiNameAlt[1]) ) +#13#10+ IntToStr( Cardinal(Pointer( Dateinamealt ))) );                    

es waren dieselben!


Nach meheren Test, war scheinbar im Read-Ereignis folgende Zeile wichtig:

Delphi-Quelltext
1:
SetLength(DateiNameNeu, Laenge);                    


in der Schreib-procedure dagegen, ist nur die Änderung, dass dort nicht ein ganzer pfad, sondern nur der Dateiname vom neuem file dort steht..
mich wundert es dass es trotzdem funktionert :O
sicherheitshalber habe ich es zu:

Delphi-Quelltext
1:
ExtractFilePath(DateiNameNeu)+DateiNameNeu                    
umgeändert (im TFileStream.create)



aber die wichtige Änderung war eben das Setlength im Read Ereignis.

user profile iconIhopeonlyReader hat folgendes geschrieben Zum zitierten Posting springen:
Edit: Beim schreiben gibt es keine fehler, aber die Datei wird nicht "größer".

Das die Größe der Datei nicht geändert wurde, stimmte scheinbar nicht, das muss ein Fehler im Windows-Explorer sein, da der Dateiname ja hinten angehängt ist!


Gerd Kayser - So 08.09.13 14:11

user profile iconIhopeonlyReader hat folgendes geschrieben Zum zitierten Posting springen:
Das die Größe der Datei nicht geändert wurde, stimmte scheinbar nicht, das muss ein Fehler im Windows-Explorer sein, da der Dateiname ja hinten angehängt ist!

Der Windowsexplorer zeigt in der normalen Ansicht die Dateigrößen nie in Bytes an. Dazu muss man sich den Eigenschaftendialog der jeweiligen Datei ansehen. Im Übrigen benutze ich da gerne einen Hex-Editor, um mir direkt ansehen zu können, was in der Datei steht.

Der Source war nur ein funktionierendes Beispiel. Die ganze Anwendung zu schreiben, hatte ich nicht die Lust und Zeit. Schließlich habe ich hier einen Fulltimejob auf vier Pfoten. ;-) Und ab und zu ein Stündchen das neue Splinter Cell Blacklist zocken will ich ja auch noch. Der Haushalt muss ja auch geführt werden.

Ob man nun Seek oder Position verwendet, ist eigentlich Jacke wie Hose. Jeder hat da seine Vorlieben. Wichtig ist da nur das Ergebnis.

Wichtig ist nicht nur die Zeile mit dem SetLength.

Delphi-Quelltext
1:
Laenge := Length(DateiNameAlt) * SizeOf(DateiNameAlt[1]);                    

Bei den neueren Delphi-Versionen sind die einzelnen Zeichen der Strings größer als ein Byte. Diese Info würde ich zusätzlich zum Dateinamen und der Länge in der Datei abspeichern und beim Lesen auswerten. Spätestens dann, wenn Du auf eine neuere Delphi-Version umsteigst, hättest Du sonst ein Problem.


IhopeonlyReader - So 08.09.13 14:14

[quote="user profile iconGerd Kayser"(679637)]
user profile iconIhopeonlyReader hat folgendes geschrieben Zum zitierten Posting springen:
Bei den neueren Delphi-Versionen sind die einzelnen Zeichen der Strings größer als ein Byte. Diese Info würde ich zusätzlich zum Dateinamen und der Länge in der Datei abspeichern und beim Lesen auswerten. Spätestens dann, wenn Du auf eine neuere Delphi-Version umsteigst, hättest Du sonst ein Problem.

ja, aber die Projekte bleiben in D7 PE... wenn ich umsteige, werde ich D7 weiterhin behalten und nicht allle Projekte "umschreiben", allgemein hast du natürlich recht