-
Notifications
You must be signed in to change notification settings - Fork 0
/
UnitSplitter.pas
120 lines (106 loc) · 3.45 KB
/
UnitSplitter.pas
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
unit UnitSplitter;
interface
uses
Windows, SysUtils, Classes,
Common, UnitBlockList, UnitBlockSorter, UnitThreadManager;
function SplitFileIntoSortedBlocks(const FileName: string; const ThreadManager: TThreadManager; const OnProgress: TProgressProc = nil): integer;
implementation
uses UnitMemoryManager, UnitMerger;
procedure ClearFiles;
begin
while Blocks.Count > 0 do
begin
DeleteFile(Blocks.FileName(Blocks.BlockNumber[0]));
Blocks.Delete;
end;
end;
{ TSplitter }
function SplitFileIntoSortedBlocks(const FileName: string; const ThreadManager: TThreadManager; const OnProgress: TProgressProc = nil): integer;
var
FS: TStream;
Buf, BufStart, BufEnd, LastChar: PAnsiChar;
ReadCnt, BlockSize: integer;
BlockRestSize: integer;
Block: PAnsiChar;
BlockIndex: integer;
BlockSorter: TBlockSorterThread;
Error: boolean;
begin
Result := 0;
try
FS := TFileStream.Create(FileName, fmOpenRead);
except
writeln('Cannot open file ', FileName);
Exit;
end;
try
Error := false;
Block := nil;
BlockSize := 0;
GetMem(Buf, SortBufferSize + 2); // äâà áàéòà íà ñëó÷àé îòñóòñòâèÿ CRLF ïîñëå ïîñëåäíåé ñòðîêè
try
BufStart := Buf;
BlockRestSize := 0; // ðàçìåð íà÷àëà ñòðîêè, íåïîëíîñòüþ ñ÷èòàâøåéñÿ â áóôåð íà ïðåäûäóùåì ïðîõîäå
repeat
ReadCnt := FS.Read(BufStart^, SortBufferSize - BlockRestSize) + BlockRestSize;
if ReadCnt > 0 then
begin
if ReadCnt > 1 then
begin
BufEnd := Buf + ReadCnt;
// Íàéäåì îêîí÷àíèå ïîñëåäíåé ñòðîêè â áëîêå
if ReadCnt < SortBufferSize then
LastChar := BufEnd // åñëè òîëüêî ÷òî ïðî÷èòàëè îñòàòîê ôàéëà, òî åãî êîíåö è åñòü îêîí÷àíèå ïîñëåäíåé ñòðîêè
else
begin
LastChar := FindLastCRLF(Buf, BufEnd);
if LastChar = nil then
begin
// åñëè â áóôåðå íå íàøëè ïåðåâîäà ñòðîêè çíà÷èò â ôàéëå åñòü ñëèøêîì äëèííàÿ ñòðîêà, íå âëåçàþùàÿ â áóôåð
writeln('Line too long!');
Error := true;
Break;
end;
// ïîäãîòîâèì áëîê äëÿ ñîðòèðîâêè - âîçüìåì òóäà âñå äî ïîñëåäíåãî ïåðåâîäà ñòðîêè
Inc(LastChar, 2); // CRLF
end;
BlockSize := LastChar - Buf;
GetMem(Block, BlockSize);
Move(Buf^, Block^, BlockSize);
// îñòàòîê ïîñëå ïåðåâîäà ñòðîêè ïåðåíåñåì â íà÷àëî áóôåðà äëÿ ñëåäóþùåãî áëîêà
BlockRestSize := BufEnd - LastChar;
Move(LastChar^, Buf^, BlockRestSize);
BufStart := Buf + BlockRestSize;
end
else
if ReadCnt = 1 then
begin
BlockSize := 1;
GetMem(Block, 1);
Block^ := Buf^;
BlockRestSize := 0;
end;
// Îòñîðòèðóåì è ñîõðàíèì â ôàéë
Inc(Result);
BlockIndex := Blocks.NextBlockNumber;
BlockSorter := TBlockSorterThread.Create(Block, BlockSize, BlockIndex);
BlockSorter.ResultFileName := Blocks.Add(BlockSorter);
ThreadManager.Run(BlockSorter);
if Assigned(OnProgress) then
OnProgress(FS.Position / FS.Size / 2);
end;
until ReadCnt = 0;
if Error then
begin
ThreadManager.WaitAllThreads;
ClearFiles;
Result := 0;
end;
finally
FreeMem(Buf);
end;
finally
FS.Free;
end;
end;
end.