Entwickler-Ecke

Dateizugriff - Datei bitweise auslesen


Flamefire - Mi 14.03.07 06:42
Titel: Datei bitweise auslesen
Hi,
ich möchte eine Text-Datei bitweise auslesen. Oder genauer: 8-Bitweise und das ergebnis dann als Integer erhalten.
Gibts da eine methode dafür?


2.) ich möchte es genauso speichern, d.h. das ebn jede der 8 Bit ersetzt werden.

3.) kann es vl sein, wenn ich die datei mal 16-bitweise auslesen will, dass es kein vielfaches von 16-bit in der datei gibt? wenn ja, wie kann ich dann das letze paar mit 0en auffüllen bis die 16bit erreicht sind, oder macht der das automatisch?

Danke schonmal


Kroko - Mi 14.03.07 07:33

???

Jede Datei wird 8 bit weise gelesen und geschrieben!

Lies sie in einen Stream (TMemoryStream) und werte die Daten dann einzeln aus!


Horst_H - Mi 14.03.07 08:46

Hallo,

eine bisher noch normale Textdatei speichert den Text zeichenweise in einem Byte char = byte und bei unicode in 2 Bytes= 1 word.
Mit Funktion Ord(..Zeichen..{z.B.: String[PosImString]}) erhälst Du den Zugriff auf den byte-Wert eines Zeichens und kannst damit machen was Du möchtest (Bit Operatoren :AND XOR OR NOT ).
Die Funktion chr(ByteWert) wandelt den Wert wieder in ein Zeichen um.

Im Grunde genommen wird nichts umgewandelt.
Man teilt dem Compiler mit:
Jetzt will ich mit den Zeichen rechnen (geht ja mit Zeichen nicht) und danach die Zahlen sind jetzt als Zeichen zu betrachten.
Es findet also nur eine Typumwandlung statt, also nichts, was den Speicher ändert, sondern nur den Umgang damit(Ausgabe, rechnen 'A'+'B'char+char'A'+'B' = 'AB' oder byte+byte ..65+66=131)

Gruß Horst


Flamefire - Mi 14.03.07 14:31

nein....nichzt ganz
es geht um RSA verschlüsselung...ich erhalte einen Integer (8Byte) den ich genauso abspeichern will, undnatürlich wieder lesen...
wenn ich den in einen char umwandle hätte ich ein prob: ascii ist ja nicht bis 65 tausend oder so ausgelegt


wulfskin - Mi 14.03.07 14:53

Hallo,

so kannst du binär eine Datei einlesen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
var
  FileStream: TFileStream;
  B: Byte; //Ein Byte (8 Bit lesen)
  S: ShortInt; //(16 Bit mit (?) Vorzeichen lesen)
  //siehe Hilfe Integer-Typen
begin
  FileStream := TFileStream.Create(DateiName, fmOpenRead or fmShareDenyWrite);
  try
    FileStream.Read(B, SizeOf(B));
    FileStream.Read(S, SizeOf(S));
  finally
    FileStream.Free;
  end;
end;
Näheres siehe Hilfe oder Forum zu Suche in: Delphi-Forum TFILESTREAM OR TSTREAM OR BIN?RE AND DATEI.

Gruß Hape!


Backslash - Mi 14.03.07 14:55

1. Wenn du eine Dateigröße hast die ungerade ist, und du immer 2 Bytes auf einmal lesen oder schreiben möchtest, dann kannst du hier mit Ganzahldivision arbeiten.


Quelltext
1:
AnzahlDatensätze := DateigrößeInBytes div DatensatzgrößeInBytes                    


Die Anzahl der letzten Bytes berechnet sich wie folgt (über Modulo)


Quelltext
1:
AnzahlLetzteBytes := DateigrößeInBytes mod DatensatzgrößeInBytes                    


2. Um die entsprechenden 8 Bits bzw. das entsprechende Byte aus einem 8 Byte Integer auszulesen, habe ich hier eine Beispielfunktion, die du für denen Fall sicherlich noch anpassen kannst. Die holt das n-te Byte aus einem Int64-Wert raus. Die Funktion ist aus formellen Gründen einfach gehalten und zeigt das Prinzip. Möchtest du das erste Byte aus dem Int64 Wert (also die ersten 8 Bits) rausholen, rufst du GetByte mit Getbyte(Wert, 0) auf.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
// Holt das n-te Byte aus einem Int64-Wert raus und gibt es zurück
function GetByte(Value : Int64; WhichByte : Integer) : Byte;
var
  i : Integer;
  AndValue : Int64;
  TempValue : Int64;
begin
  // Hinweis: Möchte man das erste Byte des Wertes bekommen, ist Whichbyte = 0
  AndValue := $FF shl (8 * (WhichByte));
  TempValue := 0;
  TempValue := AndValue AND Value;
  Result := TempValue shr (8 * (WhichByte));
end;


So schreibst du einen kompletten Int64-Wert in den den Ausgabestream


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
var
Bytewert : Int64; // Beispielwert
begin
  Bytewert := $FFFFFFFFFFFFFFFF;
  for i := 0 to 7 do
    Ausgangsstream.Write(GetByte(Bytewert, i)), SizeOf(Byte));
end;


Ich hoffe ich konnte auch diesmal helfen. Das ganze soll lediglich als konkreten Ansatz dienen. Es steht dir frei den Code auf deine Wünsche anzupassen und zu verbessern.

Gruß

Backslash

Nachtrag: Die PutByte Funktion als Umkehrfunktion zum Schreiben des entsprechenden Bytes in einen Int64 darfst du gern selbst schreiben :D


Flamefire - Mi 14.03.07 15:10

ok hab jz das:

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:
procedure TForm1.Button3Click(Sender: TObject);
var n2,d2:longint;inputf,outputf:String;f,f2:Tfilestream;b:longint;ok:boolean;
begin
ok:=false;
if input.Execute then begin// d.h. der Nutzer hat nicht Abbrechen oder so gedrückt
  inputf:=input.Filename;
    if output.Execute then begin// d.h. der Nutzer hat nicht Abbrechen oder so gedrückt
       outputf:=output.Filename;
       ok:=true;
    end;
end;
if(ok) then begin
 n2:=strtoint(Edit5.Text);
 d2:=strtoint(Edit6.Text);
  f:=TFileStream.Create(inputf,fmOpenRead);
  try
    f2:=TFileStream.Create(outputf,fmCreate);
    try
      while f.Position<f.Size do
      begin
        f.readbuffer(b,SizeOf(b));
        b := encode(b,d2,n2);
        f2.writebuffer(b,SizeOf(b));    
      end;
    finally  
      f.Free;
    end
  finally  
     f2.Free;
  end;
  showmessage('Datei entschlüsselt!');
 end;
end;


das geht auch...nur brauch er ewig =(


Backslash - Mi 14.03.07 15:19

Sag doch gleich dass du das so möchtest :D

Warum liest du die Datei nicht blockweise aus bzw. schreibst sie blockweise? Jeder Block kann ja dividiert durch SizeOf(LongInt) = 0 sein. Wenn du beispielsweise 256 Bytes, statt 8 oder gleich einen Megabyte in einen temporären Speicher einliest und diesen dann in der Schleife mit "encode" abarbeitest, dann sollte das einen argen Performancegewinn bringen :)


Kroko - Mi 14.03.07 15:57

oder nimm TMemoryStream (s.o.)


Backslash - Do 15.03.07 12:03

TMemorystream hat den Nachteil, dass der reservierte Speicher bei mir sehr schnell von Windows ausgelagert wird (habs unter win NT 4, Win 2000 und XP getestet). Dann wirds arg langsam, kann ich euch sagen. Daher verwendete ich NIE NIE NIE NIE (!!!) den Memorystream in solchen Fällen. Lieber einen TStream verwenden, weil es auch Dateien geben kann die 2 GB groß sind und dann? Hast du soviel RAM? :D

Einen temporären Puffer erstellst du mit:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
var
  TempBuf : PChar;
begin
  GetMem(TempBuf, 1048576);
  [...]
  FreeMem(TempBuf);
end;


Nachtrag: Wenn du mit großen Puffern arbeitest, empfielt es sich Getmem in einen Try-Except Block zu packen und bei Except die Funktion mit einem Fehler "Zu wenig Arbeitsspeicher." zu verlassen.