스트림이란 무엇입니까? 스트림은 간단히 말해서 객체지향 기반의 추상적인 처리 데이터입니다.
도구. 스트림에는 데이터 읽기, 데이터 쓰기 등과 같은 데이터 처리를 위한 몇 가지 기본 작업이 정의됩니다.
프로그래머는 스트림의 다른 쪽 끝에 있는 데이터의 실제 흐름 방향을 고려하지 않고 스트림에 대한 모든 작업을 수행합니다. 흐르지 않음
그러나 파일, 동적 메모리, 네트워크 데이터 및 기타 데이터 형식을 처리할 수 있습니다. 당신이 옳다면
스트림의 작동은 매우 능숙합니다. 프로그램에서 스트림의 편리함을 사용하면 프로그램 작성의 효율성이 크게 향상됩니다.
아래에서 저자는 EXE 파일 암호화기, 전자 축하 카드, 직접 만든 OICQ 및 네트워크 화면의 네 가지 예를 사용합니다.
Delphi 프로그래밍에서 "스트림"의 사용을 설명하기 위한 전송입니다. 이 예의 일부 기술은 매우 부드럽습니다.
파일의 비밀은 공개되지 않으며, 이제 누구나 무료로 직접 코드를 인용할 수 있습니다.
"높은 건물이 땅에서 솟아오른다." 사례를 분석하기 전에 먼저 흐름의 기본 개념과 개념을 이해해보자.
기능, 이러한 기본 사항을 이해한 후에야 다음 단계로 진행할 수 있습니다. 잘 이해해주세요
이러한 기본 방법. 물론, 이미 익숙하다면 이 단계를 건너뛰어도 됩니다.
1. 델파이의 스트림 기본 개념과 함수 선언
Delphi에서 모든 스트림 객체의 기본 클래스는 모든 스트림의 공통 속성을 정의하는 TStream 클래스입니다.
및 방법.
TStream 클래스에 정의된 속성은 다음과 같이 소개됩니다.
1. 크기: 이 속성은 스트림의 데이터 크기를 바이트 단위로 반환합니다.
2. 위치: 이 속성은 흐름에서 액세스 포인터의 위치를 제어합니다.
Tstream에는 네 가지 가상 메서드가 정의되어 있습니다.
1. 읽기: 이 방법은 스트림에서 데이터를 읽습니다. 함수 프로토타입은 다음과 같습니다.
함수 읽기(var Buffer;Count:Longint):Longint;virtual;abstract;
Buffer 매개변수는 데이터를 읽을 때 배치되는 버퍼이고, Count는 읽을 데이터의 바이트 수이며,
이 메서드의 반환 값은 읽은 실제 바이트 수이며, Count에 지정된 값보다 작거나 같을 수 있습니다.
2. 쓰기: 이 방법은 스트림에 데이터를 씁니다. 함수 프로토타입은 다음과 같습니다.
함수 쓰기(var Buffer;Count:Longint):Longint;virtual;abstract;
매개변수 Buffer는 스트림에 기록될 데이터의 버퍼이고, Count는 데이터 길이(바이트)입니다.
이 메서드의 반환 값은 실제로 스트림에 기록된 바이트 수입니다.
3. 탐색: 이 메서드는 스트림에서 읽기 포인터의 이동을 구현합니다. 함수 프로토타입은 다음과 같습니다.
함수 탐색(오프셋:Longint;원본:Word):Longint;가상;추상;
Offset 매개변수는 오프셋 바이트 수이며 Origin 매개변수는 Offset의 실제 의미와 가능한 값을 나타냅니다.
다음과 같이:
soFromBeginning:Offset은 이동 후 데이터의 시작 부분부터 포인터의 위치입니다. 이때 오프셋은 반드시
0보다 크거나 같습니다.
soFromCurrent:Offset은 이동 후 포인터와 현재 포인터의 상대적 위치입니다.
soFromEnd:Offset은 이동 후 데이터의 시작 부분부터 포인터의 위치입니다. 이때 오프셋은 반드시
0보다 작거나 같습니다.
이 메서드의 반환 값은 이동 후 포인터의 위치입니다.
4. Setsize: 이 방법은 데이터의 크기를 변경합니다. 함수 프로토타입은 다음과 같습니다.
함수 Setsize(NewSize:Longint);virtual;
또한 TStream 클래스에는 여러 정적 메서드도 정의되어 있습니다.
1. ReadBuffer: 이 메서드의 기능은 스트림의 현재 위치에서 데이터를 읽는 것입니다. 함수 프로토타입은 다음과 같습니다.
PRocedure ReadBuffer(var Buffer;Count:Longint);
매개변수의 정의는 위의 읽기와 동일합니다. 참고: 읽은 데이터 바이트 수가 읽어야 하는 바이트 수와 다른 경우
숫자가 다른 경우 EReadError 예외가 생성됩니다.
2. WriteBuffer: 이 메소드의 기능은 현재 위치의 스트림에 데이터를 쓰는 것입니다. 함수 프로토타입은 다음과 같습니다.
프로시저 WriteBuffer(var Buffer;Count:Longint);
매개변수 정의는 위의 쓰기와 동일합니다. 참고: 쓰여진 데이터 바이트 수가 쓰여져야 하는 바이트 수와 다른 경우
숫자가 다른 경우 EWriteError 예외가 생성됩니다.
3. CopyFrom: 이 방법은 다른 스트림에서 데이터 스트림을 복사하는 데 사용됩니다. 함수 프로토타입은 다음과 같습니다.
함수 CopyFrom(소스:TStream;Count:Longint):Longint;
매개변수 Source는 데이터를 제공하는 스트림이고 Count는 복사된 데이터 바이트 수입니다. Count가 0보다 큰 경우,
CopyFrom은 Count가 0일 때 Source 매개변수의 현재 위치에서 Count 바이트의 데이터를 복사합니다.
CopyFrom은 Source 매개 변수의 Position 속성을 0으로 설정한 다음 Source의 모든 데이터를 복사합니다.
TStream에는 다른 파생 클래스가 있으며, 가장 일반적으로 사용되는 클래스는 TFileStream 클래스입니다. TFileStream 사용
클래스를 사용하여 파일에 액세스하려면 먼저 인스턴스를 만들어야 합니다. 성명은 다음과 같습니다 :
생성자 Create(const 파일 이름:문자열;모드:Word);
Filename은 파일 이름(경로 포함)이고, Mode 매개변수는 파일을 여는 방법을 포함하는 파일을 여는 방법입니다.
개방형 모드와 공유 모드, 가능한 값과 의미는 다음과 같습니다.
개방형 모드:
fmCreate: 지정된 파일 이름으로 파일을 생성하거나, 이미 존재하는 경우 파일을 엽니다.
fmOpenRead: 지정된 파일을 읽기 전용 모드로 엽니다.
fmOpenWrite: 지정된 파일을 쓰기 전용 모드로 엽니다.
fmOpenReadWrite: 쓰기를 위해 지정된 파일을 엽니다.
공유 모드:
fmShareCompat: 공유 모드는 FCB와 호환됩니다.
fmShareExclusive: 다른 프로그램이 어떤 방식으로든 파일을 열 수 없도록 허용합니다.
fmShareDenyWrite: 다른 프로그램이 쓰기 위해 파일을 여는 것을 허용하지 않습니다.
fmShareDenyRead: 다른 프로그램이 읽기 모드에서 파일을 여는 것을 허용하지 않습니다.
fmShareDenyNone: 다른 프로그램이 어떤 방식으로든 파일을 열 수 있습니다.
TStream에는 실제 애플리케이션에서 매우 자주 사용되는 파생 클래스 TMemoryStream도 있습니다.
매우 자주. 이를 메모리 스트림이라고 하며, 이는 메모리에 스트림 개체를 생성하는 것을 의미합니다. 기본 방법과 기능은 다음과 같습니다.
위와 동일합니다.
자, 위의 기반이 마련되면 프로그래밍 여정을 시작할 수 있습니다.
------------------------------------- -------------
2. 실제 적용 1: 스트림을 사용하여 EXE 파일 암호화기, 번들, 자동 추출 파일 및 설치 프로그램 생성
먼저 EXE 파일 암호화기를 만드는 방법에 대해 이야기해 보겠습니다.
EXE 파일 암호화기의 원리: 두 개의 파일을 생성하고, 하나는 다른 EXE 파일에 리소스를 추가하는 데 사용됩니다.
내부적으로는 추가 기능 프로그램이라고 합니다. 추가되는 또 다른 EXE 파일을 헤더 파일이라고 합니다. 이 프로그램의 기능은
자신에게 추가된 파일을 읽습니다.
Windows에서 EXE 파일의 구조는 상대적으로 복잡합니다. 일부 프로그램에는 변경된 경우 체크섬이 있습니다.
나중에 그들은 바이러스에 감염되었다고 생각하고 실행을 거부할 것입니다. 그래서 우리는 프로그램에 파일을 추가합니다.
원본 파일 구조는 변경되지 않습니다. 먼저 추가 기능을 작성해 보겠습니다. 이 함수의 기능은 추가하는 것입니다.
한 파일은 다른 파일의 끝에 스트림으로 추가됩니다. 기능은 다음과 같습니다:
함수 Cjt_AddtoFile(SourceFile,TargetFile:string):Boolean;
var
대상,소스:TFileStream;
MyFileSize:정수;
시작하다
노력하다
소스:=TFileStream.Create(SourceFile,fmOpenRead 또는 fmShareExclusive);
대상:=TFileStream.Create(TargetFile,fmOpenWrite 또는 fmShareExclusive);
노력하다
Target.Seek(0,soFromEnd);//끝에 리소스 추가
Target.CopyFrom(소스,0);
MyFileSize:=Source.Size+Sizeof(MyFileSize);//리소스 크기를 계산하여 보조 프로세스 끝에 씁니다.
Target.WriteBuffer(MyFileSize,sizeof(MyFileSize));
마지막으로
대상.무료;
소스.무료;
끝;
제외하고
결과:=거짓;
출구;
끝;
결과:=참;
끝;
위의 기초를 바탕으로 이 기능을 쉽게 이해할 수 있습니다. 여기서 SourceFile 매개변수는
추가할 파일, TargetFile 매개변수는 추가할 대상 파일입니다. 예를 들어 다음 위치에 a.exe를 추가합니다.
b.exe에서는 다음을 수행할 수 있습니다. 추가가 성공하면 Cjt_AddtoFile('a.exe',b.exe'); 그렇지 않으면 True를 반환합니다.
거짓을 반환합니다.
위 함수를 기반으로 반대 읽기 함수를 작성할 수 있습니다.
함수 Cjt_LoadFromFile(SourceFile,TargetFile:string):Boolean;
var
출처:TFileStream;
대상:TMemoryStream;
MyFileSize:정수;
시작하다
노력하다
대상:=TMemoryStream.Create;
소스:=TFileStream.Create(SourceFile,fmOpenRead 또는 fmShareDenyNone);
노력하다
Source.Seek(-sizeof(MyFileSize),soFromEnd);
Source.ReadBuffer(MyFileSize,sizeof(MyFileSize));//리소스 크기 읽기
Source.Seek(-MyFileSize,soFromEnd);//리소스 위치 찾기
Target.CopyFrom(Source,MyFileSize-sizeof(MyFileSize));//리소스 제거
Target.SaveToFile(TargetFile);//파일에 저장
마지막으로
대상.무료;
소스.무료;
끝;
제외하고
결과:=거짓;
출구;
끝;
결과:=true;
끝;
SourceFile 파라미터는 추가된 파일의 파일명이고, TargetFile 파라미터는 꺼낸 파일명이다.
파일 뒤에 저장할 대상 파일 이름입니다. 예를 들어 b.exe의 Cjt_LoadFromFile('b.exe','a.txt');
파일을 꺼내서 a.txt로 저장하세요. 추출이 성공하면 True를 반환하고 그렇지 않으면 False를 반환합니다.
Delphi를 열고 새 프로젝트를 만든 다음 편집 컨트롤 Edit1과 두 개의 버튼을 창에 놓습니다.
버튼1과 버튼2. 단추의 캡션 속성은 각각 "확인"과 "취소"로 설정됩니다. 존재하다
Button1의 Click 이벤트에 코드를 작성합니다.
var S: 문자열;
시작하다
S:=ChangeFileExt(application.ExeName,'.Cjt');
Edit1.Text='790617'이면
시작하다
Cjt_LoadFromFile(Application.ExeName,S);
{파일을 꺼내서 현재 경로에 저장하고 이름을 "original file.Cjt"로 지정하세요.}
Winexec(pchar(S),SW_Show);{"원본 파일.Cjt" 실행}
신청.종료;{프로그램 종료}
끝
또 다른
Application.MessageBox('비밀번호가 틀렸습니다. 다시 입력해주세요!', '비밀번호가 틀렸습니다.', MB_ICONERROR+MB_OK);
이 프로그램을 컴파일하고 EXE 파일의 이름을 head.exe로 바꿉니다. 새 텍스트 파일 head.rc를 만듭니다.
내용은 다음과 같습니다: head exefile head.exe, 그런 다음 이를 Delphi의 BIN 디렉터리에 복사하고 실행합니다.
Dos 명령 Brcc32.exe head.rc는 head.res 파일을 생성합니다.
리소스 파일을 먼저 보관하세요.
헤더 파일이 생성되었습니다. 추가 기능 프로그램을 만들어 보겠습니다.
새 프로젝트를 만들고 다음 컨트롤을 추가합니다: 하나의 편집, 하나의 Opendialog 및 두 개의 Button1
캡션 속성은 각각 "파일 선택" 및 "암호화됨"으로 설정됩니다.
소스 프로그램에 {$R head.res}라는 문장을 추가하고 head.res 파일을 프로그램의 현재 디렉터리에 복사합니다.
이런 식으로 방금 head.exe가 프로그램과 함께 컴파일됩니다.
Button1의 Clck 이벤트에 코드를 작성합니다.
if OpenDialog1.Execute then Edit1.Text:=OpenDialog1.FileName;
Button2의 Clck 이벤트에 코드를 작성합니다.
var S:문자열;
시작하다
S:=ExtractFilePath(Edit1.Text);
if ExtractRes('exefile','head',S+'head.exe') 그러면
if Cjt_AddtoFile(Edit1.Text,S+'head.exe') 그러면
if DeleteFile(Edit1.Text) 다음
if RenameFile(S+'head.exe',Edit1.Text) 그런 다음
Application.MessageBox('파일 암호화에 성공했습니다!','메시지',MB_ICONINFORMATION+MB_OK)
또 다른
시작하다
if FileExists(S+'head.exe') then DeleteFile(S+'head.exe');
Application.MessageBox('파일 암호화에 실패했습니다!','메시지',MB_ICONINFORMATION+MB_OK)
끝;
끝;
그 중 ExtractRes는 리소스 파일에서 head.exe를 추출하는 데 사용되는 사용자 정의 함수입니다.
함수 ExtractRes(ResType, ResName, ResNewName : String):boolean;
var
해상도: TResourceStream;
시작하다
노력하다
Res := TResourceStream.Create(Hinstance, Resname, Pchar(ResType));
노력하다
Res.SavetoFile(ResNewName);
결과:=true;
마지막으로
해상도 무료;
끝;
제외하고
결과:=거짓;
끝;
끝;
참고: 위의 기능은 단순히 한 파일을 다른 파일의 끝에 추가합니다.
실제 응용에서는 오프셋이 실제 크기와 개수에 따라 정의되는 한 여러 파일을 추가하도록 변경할 수 있습니다.
주소가 됩니다. 예를 들어, 파일 번들러는 헤더 파일에 두 개 이상의 프로그램을 추가합니다.
안에. 자동 압축 풀기 프로그램과 설치 프로그램의 원리는 동일하지만 압축률이 더 높습니다.
예를 들어 LAH 단위를 참조하고 스트림을 압축한 다음 추가하면 파일이 더 작아집니다.
읽기 전에 압축을 풀면 됩니다.
또한 기사에 나오는 EXE 암호화기의 예에는 여전히 많은 결함이 있습니다. 예를 들어 비밀번호는 다음과 같이 고정되어 있습니다.
"790617", EXE를 꺼내 실행한 후 실행이 끝날 때까지 기다렸다가 삭제하는 등의 작업을 수행해야 합니다. 독자가 직접 수정할 수 있습니다.