PDA

View Full Version : Giải thuật sao chép File !


Mapcon
11-04-2003, 06:22 PM
ngờ uồn Tạp chí Tin học & nhà trường .
Tui thấy cũng đọc được nên post (post nguyên bản vì ko có thời gian edit lại :D) lên trên đây cho vui, ai quan tâm thì ngó chút . ;) :D
-------------------------------------------------

Sao chép files trong chế độ real-mode MS-DOS thì tốc độ chậm hơn hẳn so với Windows. Có nhiều lý do khác nhau, nhưng một trong những lýdo chính là các giải thuật sao chép files trong Windows được cải thiện hơn và có phần tối ưu hơn so với các phương thức sao chép files trong DOS. Tuy nhiên, ta vẫn có thể cải thiện vấn đề bằng cách tìm chương trình SMARTDRV.EXE và gõ lệnh SMARTDRV C+ ở DOS. Vấn đề này sẽ được đề cập kĩ hơn dưới đây.
Trong bài viết này tôi không có ý định đưa ra các đặc tính kĩ thuật của Windows hay của SMARTDRV.EXE, mà chỉ muốn cung cấp cho bạn đọc những ý tưởng chính của việc sao chép files, và một vài vấn đề cho bạn đọc tham khảo.

Để sao chép file trong Pascal, bạn cần phải biết các thao tác xử lý vào/ra file cơ bản, một vài lệnh và hàm vào/ra file thông dụng của Pascal như Reset, Rewrite, Eof, Close, Assign,… Khi viết một ứng dụng hoàn chỉnh bạn đọc cần bổ sung phần xử lý lỗi (dùng macro{$I-} {$I+} và hàm ioresult…) vào các chương trình mẫu dưới đây.
Giải thuật sao chép files đơn giản nhất
Để sao chép file, điều đầu tiên ta có thể nghĩ đến là đọc từng byte của file này và ghi vào file kia.
Minh họa ý tưởng này như sau:
Var f1: file of char;
f2: text;
ch: char;
Begin
If paramcount<>2 then exit;
Assign(f1,paramstr(1));reset(f1);
Assign(f2,paramstr(2));rewrite(f2);
While not eof(f1) do
Begin
Read(f1,ch);
Write(f2,ch);
End;
Close(f1);
Close(f2);
End.
Chú ý: Nếu f1 được khai báo kiểu text thì chương trình sẽ hoạt động sai, do các files ta chỉ ra có thể không phải là file văn bản. Và trong các chương trình giới thiệu ở đây, tôi giả thiết rằng nó làm việc trong điều kiện tối ưu, không có lỗi.
Chương trình trên hoạt động bình thường. Tuy nhiên, tốc độ quá chậm, đôi khi còn chậm hơn việc download từ Internet, phải mất gần 1 phút mới chép xong 1 file vài trăm KB. Và tốc độ này càng chậm hơn khi hoạt động trên đĩa mềm
Vì sao? Giả sử rằng chúng ta cần di chuyển n (n khá lớn) vật. Nếu một lần bạn chỉ di chuyển 1 vật thì có thể sẽ tốn thời gian. Và bạn cũng không thể di chuyển một lần cả n vật. Trên máy tính cũng vậy, nếu mỗi lần chỉ đọc và ghi 1 byte, thì máy sẽ cất và chuyển dịch đầu đọc nhiều lần, tốn thời gian.
Để cải thiện tốc độ, mỗi lần ta phải di chuyển x vật (0 < x < n+1) sao cho ít tốn công nhất, hay nói cách khác mỗi lần phải sao chép x bytes sao cho tốc độ sao chép là nhanh nhất. Đối với Pascal x < 64 KB, và 64KB cũng là số x thường được sử dụng trong Windows.
Đến đây chắc hẳn bạn đã hiểu SMARTDRV.EXE hoạt động ra sao. Giả sử chương trình chúng ta mỗi lần ghi 1 byte vào đĩa, nó sẽ cất trong vùng đệm (buffer) đến chừng nào đủ x bytes thì mới ghi, nên cải thiện được đáng kể tốc độ chép. Tuy nhiên, nếu chương trình chúng ta mỗi lần đọc 1 byte, thì SMARTDRV (và cả Windows) có thể sẽ chẳng giúp nhiều.
Mở rộng − tối ưu hóa giải thuật (optimizing algorithm)
Vậy thì chúng ta sẽ đọc một lần n bytes, và sau khi đã đọc đủ n bytes thì sẽ ghi n bytes đó ra đĩa. ở đây tôi chỉ minh họa giải thuật, bạn đọc tự mình xử lý trường hợp nếu như chưa đọc đủ kn bytes mà đã hết file (k > 0), nếu không chương trình sao chép sẽ làm mất dữ liệu, file kết quả bao giờ cũng có kích cỡ chia hết cho n.
Const nmax=32*1024;
Var f1: file of char;
F2: text;
a: array[1..nmax] of char;
i: longint;
Begin
If paramcount<>2 then exit;
Assign(f1,paramstr(1));reset(f1);
Assign(f2,paramstr(2));rewrite(f2);
While not eof(f1) do
Begin
For i:=1 to nmax do Read(f1,a[i]);
For i:=1 to nmax do Write(f2,a[i]);
End;
Close(f1);
Close(f2);
End.
Chương trình trên đây dù có nhanh hơn chưong trình ban đầu, nhưng vẫn còn quá chậm, bởi vì cho dù chúng ta đã đọc một lần n bytes, rồi ghi n bytes thế nhưng, chúng ta vẫn bắt buộc máy phải đọc mỗi lần một byte rồi cất chúng vào mảng a gọi là vùng đệm, rồi mới sao chép. Vì vậy thực chất máy vẫn phải di chuyển đầu đọc nhiều lần. Bạn đọc có thể sửa mảng a thành mảng của các chuỗi kí tự, rồi sửa chữa các biến khác cho phù hợp thì thấy tốc độ sao chép nhanh hơn (vì mỗi lần chuyển đầu đọc, máy đọc 255 bytes). Tuy nhiên bạn sẽ phải sửa chữa nmax thành nhỏ hơn (vì Pascal chỉ hỗ trợ dữ liệu đến 64KB) và việc xử lý trong chương trình sẽ vô cùng phức tạp. Rõ ràng sao chép files theo kiểu này là không hiệu quả.
Có thể bạn chưa biết nhưng Pascal hỗ trợ BlockRead và BlockWrite để sao chép file rất nhanh. Pascal chuẩn của Niklaus Wirth không có các lệnh này, nhưng hãng Borland và những người cải thiện Pascal thế hệ sau đã thêm cho Pascal đặc tính tuyệt vời đó.
Lệnh này đọc mỗi lần n bytes (cất vào vùng đệm) hay ít hơn nếu đã hết file vào bộ nhớ, sau đó có thể dùng BlockWrite để ghi ra đĩa với cú pháp tương tự như BlockRead. Máy tự xử lý vấn đề đọc được bao nhiêu bytes,... người dùng không cần quan tâm. Chỉ với một vài câu lệnh đơn giản, ta có một chương trình sao chép file tương đối tốt (không xử lý lỗi) như sau:
var
FromF, ToF: file;
NumRead, NumWritten: Word;
Buf: array[1..63*1024] of Char;
begin
Assign(FromF, ParamStr(1)); {Open input file}
Reset(FromF, 1); { Record size = 1 }
Assign(ToF, ParamStr(2)); {Open output file}
Rewrite(ToF, 1); { Record size = 1 }
Writeln('Copying ', FileSize(FromF), ' bytes...');
repeat
BlockRead(FromF, Buf, SizeOf(Buf), NumRead);
BlockWrite(ToF, Buf, NumRead, NumWritten);
until (NumRead = 0) or (NumWritten <> NumRead);
Close(FromF);
Close(ToF);
end.
Rõ ràng là chương trình này hiệu quả hơn hẳn, chép nhanh và ít sai sót hơn các chương trình ở trên. Bạn có thể tự bổ sung các phần kiểm tra lỗi khi chép. Dưới đây tôi chỉ minh hoạ cách mở rộng chương trình cho nhiều files.

ước tính thời lượng sao chép như trong Windows

Ta sẽ có công thức ước lượng thời gian còn lại trong quá trình sao chép file như sau:
Remaining = Elapsed x (Copied/Total - 1)
Bạn hãy tự chứng minh công thức trên và một cách tương tự, ước tính được tốc độ của quá trình sao chép file (KB/s)
Mở rộng cho nhiều files. Để sao chép nhiều files, bạn có thể sửa chữa chương trình mẫu ở trên thành một chương trình con và dùng FindFirst, FindNext để sao chép nhiều file trong cùng một thư mục.
Minh hoa ý tưởng này như sau:
uses Dos;
var DirInfo: SearchRec;
................
Procedure CopyFile(source, dest:string);
................
Procedure Prepare;
................
BEGIN
Prepare;
ChDir(SourceDir);
FindFirst(filemask, Archive, DirInfo);
while DosError = 0 do
begin
Writeln(DirInfo.Name);
................
NewFile:=Dest+′′+DirInfo.Name;
CopyFile(source,NewFile);
................
FindNext(DirInfo);
end;
................
END.
Trong đó Prepare là thủ tục test tham số, phân tích dạng file cần chép (filemask) và thư mục ngờ uốn (sourcedir) và đích đến (dest). Trong lệnh gọi CopyFile, source là tên file cần chép còn NewFile là tên file mới. Bạn đọc tự bổ sung những phần còn lại.
Duyệt cây thư mục dùng phép đệ quy (recursion) theo chiều sâu (depth)
Sau đây tôi minh hoạ cách duyệt tất cả các thư mục con của một thư mục. Bạn đọc tự bổ sung các thao tác như copy, move,... nếu muốn
{$M $FFF0,0,0}
Uses Dos;
Const {File Attributes Declarations}
ReadOnly=$01; Hiđen=$02; SysFile=$04; VolumeID=$08;
Directory=$10; Archive=$20; Anyfile=$3F;
................
Procedure Browse(path:string);
Var DirInfo:SearchRec;Attr:Word;
................
Begin
Path:=Path+′′;
FindFirst(Path+′*.*′,Anyfile-VolumeID, DirInfo);
While DosError=0 do
Begin
If (DirInfo.Attr=Directory) and (DirInfo.name<>′.′) and (DirInfo.Name <>′..′)
then Browse(path+DirInfo.name) {Continue browsing}
else if (DirInfo.name<>′.′) and (DirInfo.name <>′..′)
then ................ {Process the file};
FindNext(DirInfo);
End;
................
Macro $M trước chương trình tăng kích cỡ stack lên tối đa, nếu không, khi phải duyệt quá nhiều cấp thư mục g nhau dễ gây tràn stack và máy báo lỗi Runtime Error 005 (Stack Overflow Error)

Giải thuật di chuyển bấy lâu nay là moving=copying+deleting (di chuyển = sao chép + xóa). Với giải thuật này việc di chuyển sẽ chậm. Nếu say mê Asembly, bạn đọc có thể dùng hàm 56HEX (DOS 2+) [Rename/Move] để cải thiện giải thuật. Hàm này chỉ di chuyển điểm vào (entry point) của file trong bảng FAT, mà không thực sự di chuyển file.

Ngô Từ
11-04-2003, 09:40 PM
Chú Mập chịu khó thật, anh cũng muốn vào tán cho vui nhưng khổ nỗi anh chả biết chi pascal cả [-(. Hi hi. Chú Mập khi nào thử cài lại bằng C cho anh em tham khảo với.

Good work.

Nothing
11-04-2003, 09:51 PM
Originally posted by DQYEN@Apr 11 2003, 07:40 PM
Chú Mập chịu khó thật, anh cũng muốn vào tán cho vui nhưng khổ nỗi anh chả biết chi pascal cả [-(. Hi hi. Chú Mập khi nào thử cài lại bằng C cho anh em tham khảo với.

Good work.
Giả vờ giả vịt . Khinh Pascal à ??
Th.ằng quái nào mà chả học Pascal khi mới lơ ngơ vào nghề . Ông thì cứ nhiễu !

Ngô Từ
11-04-2003, 10:07 PM
Th.ằng quái nào mà chả học Pascal khi mới lơ ngơ vào nghề . Ông thì cứ nhiễu !

Khà khà. Bỏ cái filter chữ "thằng" rồi ông ạ. Dạo này học AI có vẻ yêu pascal nhỉ? Có khi ông sau này đi dạy chuyên Tin được đấy. Còn tôi học pascal cũng tương đối cơ bản đấy - quay lui vét cạn - duyệt sâu loang rộng :D - Nhánh cận - Dijkstra - ... chỉ thiếu mỗi luồng thôi đấy. Còn những bài nào mà dùng đến kiến thức Toán thì lại là sở trường rồi. À mà cũng phải cám ơn trường Bưu Chính đã dạy cho mình những cái này hồi năm một - do em đi học ké đội tuyển Tin của trường. Học với thầy My sướng thật - còn thầy Quốc chả bao giờ có đáp án hết - chỉ nói qua qua hi hi. Còn thầy My thì code lời giải rất khó đọc :(

Nhưng mà nói thật là chú Mập viết khó đọc quá.

huyenmy
12-04-2003, 08:41 AM
hic hic em chịu chẳng biết pascal là giè hichic. Vào nghề..... chắc em không theo tin học :P :P

Nothing
12-04-2003, 10:53 AM
Ông biết ko , mãi đến bây giờ tôi mới đủ kiên nhẫn để đọc code người khác viết đấy . Hồi mới học tôi cực ghét là phải châm cứu đống code dài cả trang giấy . Nhưng bây giờ mới biết hồi đó học Data Struct và Toán rời rạc nhỉ ? rất là cần thiết .
Năm ngoái đồ án thực tập cơ sở là tôi làm mô phỏng bài toán "Người du lịch" bằng Java đấy ,dùng Dijkstra .

Mapcon
13-04-2003, 08:19 PM
.... hi hi ông bác bỏ phần luồng là bỏ cả một mảng lớn của các bài toán Tin học đấy, luồng khó hiểu thật nhưng ứng dụng của nó rất lớn ví dụ như trong mạng vận tải, hay trong thiết kế mạng máy tính ngoài việc sử dụng Dijkstra để tìm đường đi ngắn nhất thì còn dùng luồng để giải quyết vấn đề như "luồng chảy thông tin trong mạng " hay cái gì đại loại thế :D . Nói thật bác em cũng quên khá nhiều luồng roài ...:P. Em có coi cái giáo trình của bọn Sing và cái Textbook của bọn Academy Japan thì nó cũng chỉ đề cập mấy cái như : Prim , Kruskal, Dijkstra thôi không nói chi đến luồng .
...bác Trà đang học AI a` ! thầy Nghĩa dạy à bác, chắc là rắc rối đấy nhẩy ! lại ví dụ điển hình Tic Tac Toe :D rồi mấy cái mạng Neraul nữa chứ...coi mà muốn mù cả mắt !
Nhưng mà nói thật là chú Mập viết khó đọc quá.
em không hiểu :-/ ...em đã bảo lấy nguyên văn từ Tạp chí Tin học & Nhà trường rồi cơ mà => người khác viết ...:D
Chú Mập khi nào thử cài lại bằng C cho anh em tham khảo với. ..em cũng muốn cài lại bằng C . Nhưng để lúc nào em có thời gian ...giờ đang bận chút ....

Ông biết ko , mãi đến bây giờ tôi mới đủ kiên nhẫn để đọc code người khác viết đấy . Hồi mới học tôi cực ghét là phải châm cứu đống code dài cả trang giấy . Nhưng bây giờ mới biết hồi đó học Data Struct và Toán rời rạc nhỉ ? rất là cần thiết .
hi hi đọc được code của người khác mà hiểu được là một điều may mắn đấy :D
mỗi thằng viết một kiểu => khó hiểu. Nhưng nếu hiểu được thì học được cách làm của người ta và cả phong cách viết chương trình nữa .

Năm ngoái đồ án thực tập cơ sở là tôi làm mô phỏng bài toán "Người du lịch" bằng Java đấy ,dùng Dijkstra .
... một bài toán "đểu" cứ Dijkstra là xong , chả phải cải tiến cái gì . Java , C hay Pascal đều giống nhau :D

Nothing
14-04-2003, 12:34 AM
Ku em nhầm ở chỗ cho là nó là "bài toán đểu" rồi . Chú ý cái đề bài của anh là Mô phỏng
Thực ra cũng chẳng có gì , có điều chỉ đọc và làm trong vòng 3 tuần , vừa đọc ngôn ngữ , lần đầu tiên làm quen với kiểu Visual design form , mouse event các kiểu thì cũng ko tệ nhỉ ??
Mô phỏng , nghĩa là ta phải tạo ra một đống nút , nhìn trực quan , rồi lấy chuột bắt kéo các cung , xong rồi nhập vào bằng textbox hai nút đầu cuối --> hiển thị đường đi trên đồ thị vừa vẽ xong . Nói chung là xử lý mấy cái kia mới là lâu , chứ cài đặt thuật toán thì đúng là bê nguyên xi từ Pascal sang Java thôi . Nói thật với chú chứ , để xài được hàm Paint ko phải là chuyện đùa đâu ku ạ , nhất là với những chú tư duy lập trình cấu trúc quen rồi ( Ví dụ như ku đấy ) . :P
++++++++
À , cái chương trình đánh cờ kia là anh viết bằng VB , hi hi , học VC++ khoai quá , đek kịp làm nên làm VB cho nó dễ . Khà khà , ko chuyên nghiệp nhỉ ??

hmt
20-04-2003, 11:33 PM
nhưng mà mình không hiểu bào "người du lịch " thì dijktrakiểu gì?
hic hic :((

Nothing
21-04-2003, 12:04 AM
Originally posted by hmt@Apr 20 2003, 09:33 PM
nhưng mà mình không hiểu bào "người du lịch " thì dijktrakiểu gì?
hic hic :((
Chú thật hay đùa đấy ?? [-x [-x [-x
Hình như chính xác là tìm đường đi ngắn nhất .

epymol
22-04-2003, 03:04 PM
Năm ngoái đồ án thực tập cơ sở là tôi làm mô phỏng bài toán "Người du lịch" bằng Java đấy ,dùng Dijkstra .
Ông anh làm mô phỏng rùi à. Gửi cho em file ngờ uồn đc ko?

hmt
23-04-2003, 05:06 PM
Xin lỗi bác nhưng tìm đường đi ngắn nhất bình thường không thể giải được bài "người du lịch".
Bài toán "Người Du Lịch":
Có n thành phố ,được đánh số từ 1->n.Khoảng cách từ tp i đến tp j là a[i,j].Một người đang ở tp 1 ,anh ta muốn đi du lịch qua tất cả n Tp nhưng mỗi Tp chỉ qua đúng 1 lần.Hãy tìm hành trình cho người đó sao cho tổng quãng đường phải đi là ngắn nhất.
Bác nào giải được bằng Dijktra thì xin hãy nhận HMT này 1 lạy .hic hic :((

hoctrodot
23-04-2003, 06:03 PM
Originally posted by Mapcon@Apr 13 2003, 06:19 PM
...bác Trà đang học AI a` ! thầy Nghĩa dạy à bác, chắc là rắc rối đấy nhẩy ! lại ví dụ điển hình Tic Tac Toe :D rồi mấy cái mạng Neraul nữa chứ...coi mà muốn mù cả mắt !

Chú mập nhầm rồi, Mr Nghĩa chỉ dạy Toán rời rạc và tối ưu hoá thôi (bây giờ mở rộng thành tính toán khoa học). Còn môn AI này là thầy Nguyễn Thanh Thuỷ dạy. Nhưng năm ngoái, khi bọn anh học, Mr Thuỷ đi Mỹ nên Mr Đức dạy thay. Bây giờ thì Mr Đức lại đi Nhật rồi.

Còn bài toán người du lịch hiện chưa có thuật giải tối ưu, chỉ dùng phương pháp đệ quy vét cạn và đánh giá nhánh cận. Nhưng kết quả đến đâu còn tuỳ thuộc "hoàn cảnh". Bác nào biết thuật giải tối ưu rồi thì học trò dốt xin tôn làm sư phụ!

Bảo Kê
23-04-2003, 07:23 PM
Miẹ kiếp , tôi nhớ nhầm , xin lỗi mọi người . Chính xác là bài toán tìm đường đi ngắn nhất . Giải bằng Dijkstra thật .
Còn bài toán "Người du lịch " là dùng Nhánh Cận . Thế quái nào mình thường xuyên nhầm hai bài này nhể .
Xin lỗi chú Nam .
To em Epymol : Rất tiếc , hồi đầu mới online từ nhà , anh bị hacker cài hai file lạ vào máy đã format mất hai partition nên đã ko giữ được . Nói chung là cũng bình thường , chủ yếu là mấy cái sự kiện của con chuột phong phú hơn VB tý thôi .

Mapcon
23-04-2003, 07:40 PM
Bỏ mẹ ! thằng em lâu ngay ko coi mấy thứ đó cũng quên mất ....hic ...làm gì có giải thuật nào tối ưu cho bài toán " Người du lịch ", chỉ dùng có thể dùng nhánh cận theo em biết !!! . ...chuối vật ra.. hi hi hmt quả ko hổ danh hi hi :D