2013-07-11 4 views
2

이진 파일을 읽고 메모에 결과를 표시하고 싶지만 "이 유형과 호환되지 않는 유형 : '문자열'및 '배열' '코드는델파이에서 이진 파일 읽기

입니다.
unit yo; 

interface 

uses 
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
    Dialogs, StdCtrls; 

type 
    TForm1 = class(TForm) 
    Button1: TButton; 
    Memo1: TMemo; 
    Button2: TButton; 
    procedure Button1Click(Sender: TObject); 
    procedure Button2Click(Sender: TObject); 
    private 
    { Private declarations } 
    public 
    { Public declarations } 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.dfm} 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    F: TFileStream; 
    Buffer: array [0 .. 1023] of byte; 
begin 

    F := TFileStream.Create(ExtractFilePath(Application.ExeName) 
     + 'yo.exe', fmOpenRead); 

    while F.Position < F.Size do 
    begin 

    F.Read(Buffer, 1024); 
    Memo1.Lines.Add(Buffer); 

    end; 

    F.Free; 

end; 

이 오류가 발생하지 않도록 피할 수 있으며 오류없이 프로그램을 실행할 수 있습니까?

누구든지 나를 도와 줄 수 있습니까?

+0

음, 파일의 텍스트 인코딩이 무엇 :

for i := Low(Buffer) to High(Buffer) do begin if (i = BytesRead) then begin Buffer[i] := #0; // Mark the end of the buffer and exit loop; Break; end else if (Buffer[i] = #0) then Buffer[i] := 'Ø'; end; 

여기에 전체 단일 버퍼를 읽기의 출력이있다 : 당신은 같은 것을 사용하는 for 루프를 변경할 수 있습니까? –

+0

@DavidHeffernan : 텍스트가 아닙니다. 포스터는 .EXE 파일의 내용을 메모에 1K 바이트 단위로 표시하려고합니다. ??? –

+0

... EXE에 포함 된 텍스트가 UTF-16 일 가능성이 있습니까? –

답변

10

stringarray[] of Byte을 직접 할당 할 수 없기 때문에이 오류를 직접 무시할 수 없습니다.

이후 바이너리 내용 (특히 #0 문자, 또는 0x00 16 진수 값 (C/C++)) 디스플레이되지 않습니다 어쨌든 (텍스트가 처음 #0 값으로 종료 될 것입니다)를 TMemo, 당신은 좋겠에서 그것을 대체해야합니다.

쉬운 방법은 컴파일러 오류가 array[] of Byte에서 직접 string에 할당 할 수 있습니다 array[] of AnsiChar에 배열을 변경하는 것입니다 과거를 얻을 (또는 1에 형태 캐스트)합니다 :

var 
    Buffer: array[0..1023] of AnsiChar; 
    TempStr: string; 
begin 
    // Fill buffer from stream 
    TempStr := Buffer; 
    Memo1.Lines.Add(TempStr); 
    // The next line eliminates the need for `TempStr` 
    // Memo1.Lines.Add(String(Buffer)); 
end; 

그러나, 같은 나는 이것이 메모에 표시하는 문제를 해결하지 못할 것이라고 말했다. 예를 들어 실제로 Windows 실행 파일을 읽을 때 첫 번째 버퍼는 MZP을 표시합니다. 네 번째 바이트는 #0이고 메모는 문자열을 종료하기 때문입니다.

이 제한을 극복하려면 #0 문자를 다른 것으로 바꿔야합니다. 그 문제는 당연히 당신이 바꿀 수있는 어떤 값도 실제로는 실행 파일에서 발생할 수 있다는 것입니다 (바이트이기 때문에 가능한 값은 256 개뿐입니다).

var 
    Buffer: array[0..1023] of AnsiChar; 
    i: Integer; 
    TempStr: string; 
begin 
    // Fill buffer as before 
    for i := Low(Buffer) to High(Buffer) do 
    if Buffer[i] = #0 then 
     Buffer[i] := `Ø`;  // Try #144 instead 
    TempStr := Buffer; 
    Memo1.Lines.Add(TempStr); 
    // You can still eliminate the string variable by typecasting 
    // Memo1.Lines.Add(String(TempStr)); 
end; 

여기서, 실제로 델파이 콘솔 응용 프로그램에서 1K 버퍼를 읽는 TForm.FormCreate 이벤트에 대한 코드가의 위의 교체를 수행하고 디스플레이 : 다시, 간단한 해결책은 0 (# 216) 모든 #0 문자를 대체하는 것입니다 TMemo의 콘텐츠 TMemo을 양식에 놓고 Alignment 속성을 alClient으로 설정하고 ScrollBarsssVertical으로 설정합니다. 폼에 FormCreate 이벤트 핸들러를 추가하고 해당 이벤트에 대한 다음과 같은 코드를 사용

procedure TForm1.FormCreate(Sender: TObject); 
var 
    Stream: TFileStream; 
    Buffer: array[0..1023] of AnsiChar; 
    TempStr: string; 
    i: Integer; 
begin 
    Memo1.Clear; 
    // Populate buffer elements 
    Stream := TFileStream.Create('D:\Temp\Project2.exe', fmOpenRead); 
    try 
    Stream.Read(Buffer[0], SizeOf(Buffer)); 
    finally 
    Stream.Free; 
    end; 
    // Replace null (#0) values with #216 (Ø) 
    for i := Low(Buffer) to High(Buffer) do 
    if Buffer[i] = #0 then 
     Buffer[i] := 'Ø'; 
    TempStr := Buffer; 
    Memo1.Lines.Add(TempStr); 
end; 

참고 : 실제로 대신 첫 번째 버퍼의 전체 이진 파일을 읽는 경우, 마지막 버퍼가되지 않을 수도 있습니다 완전히 파일 내용으로 가득 차 있습니다 (마지막 단계에서 전체 버퍼를 읽을 수 없음). 이 경우, 버퍼의 끝을 #0으로 표시하여 메모가 부분 버퍼를 올바르게 표시하도록합니다.

Executable displayed in TMemo

+1

오, 이런 대답이 크다. +1 –

+2

좋은데, 나를 도와 주신 모든 분들께 해결책을 찾아 주셨습니다.하지만 왜 모두 저에게 부정적인 표를 던지지만 여전히 그들에게 은혜를주고 있습니다. – 14K

6

바이트 배열은 문자열이 아니므로 컴파일러의 메시지는 정확히 말합니다. 바이트는 숫자입니다. 문자열은 텍스트입니다. 숫자는 텍스트가 아니므로 프로세스의 어느 곳에서나 숫자를 텍스트로 변환하는 방법을 프로그램에 알려줘야합니다.

한 가지 방법은 각 숫자 값을 해당 숫자로 변환하는 것입니다. 예를 들면 :

F.Read(Buffer, 1024); 
s := ''; 
for b in Buffer do 
    s := s + IntToStr(b); 
Memo1.Lines.Add(s); 

각 바이트는, 해당 숫자 값으로 문자으로 변환 한 후 당신이 정말로 전혀 변환이 필요하지 않습니다 싶은 경우에; 단지 거짓말을하고 메모 컨트롤에 직접로드 할 수 있도록 파일이 텍스트를 포함하는 프로그램을 말씀 :있는 그대로

Memo1.Lines.LoadFromFile(FileName); 

당신은 인쇄 가능한 문자를 표시 할 수있는 파일의 바이트를 원하는 경우

가 표시하고, 인쇄 할 수없는 문자를 나타내는 사람은 당신은 유사 위의 루프에 별도로 각 문자를 처리 할 수있는, 숫자 표시하기 :

F.Read(Buffer, 1024); 
s := ''; 
for b in Buffer do begin 
    c := AnsiChar(b); 
    if TCharacter.IsControl(c) then 
    s := s + IntToStr(b) 
    else 
    s := s + c; 
end; 
Memo1.Lines.Add(s); 

당신은 당신이 원하는 방식으로 데이터 변환을 정의 할 수 있습니다. 원하는 출력을 지정하고 출력을 생성하는 코드를 작성하면됩니다. 원하는 것을 지정하지 않았고 정확하게 설명 할 수없는 경우 아직 코드를 사용할 준비가되지 않았습니다.