في نافذة الطباعة اختر «حفظ كملف PDF» كوجهة.
نظم التشغيل 1، الدرس العملي 3
كيف ينقل البرنامج البايتات إلى الملفات ومنها، وكيف يتجول في المجلدات التي تحفظها
IDisposable وDispose() وجملة usingFileStream بالقيم الصحيحة من FileMode وFileAccess وFileShare، وتوقع Position وLengthStreamReader / StreamWriter، والقيم باستخدام BinaryReader / BinaryWriterFile والمزخرف DeflateStreamDirectory وDirectoryInfo وFileInfoالجزء 1
بايتات تتدفق بين البرنامج والعالم الخارجي
ملف نصي جديد لا يحتوي إلا A. ثم يحتوي A وأربع مسافات وz. كم بايتا في كل مرة؟
Size: 1 byte(s)
Size: 6 byte(s)
65 = 01000001 = 'A'
32 = 00100000 = ' '
32 = 00100000 = ' '
32 = 00100000 = ' '
32 = 00100000 = ' '
122 = 01111010 = 'z'A هو الرقم 65، والمسافة 32، وz هو 122المصدر الخارجي
ملف، شبكة
المخزن الخلفي
FileStream
المزخرف
DeflateStream
المحول
StreamReader، BinaryWriter
برنامجك
الجزء 2
من يغلق الملف؟
الملف المفتوح مقبض من نظام التشغيل (handle) لا يتتبعه جامع المهملات: لذا ينفذ صنفه IDisposable، وعليك أنت أن تستدعي Dispose().
class LogFile : IDisposable
{
private readonly FileStream fs;
private bool disposed = false;
public void Dispose()
{ Dispose(true); GC.SuppressFinalize(this); }
protected virtual void Dispose(bool disposing)
{
if (disposed) return;
if (disposing) fs.Dispose();
disposed = true;
}
~LogFile() { Dispose(false); }
}IDisposableDispose() عامة (public) لمستخدمي الصنفDispose(bool) محمية افتراضية (protected virtual) تؤدي العمل؛ ويجعلها العلم disposed تعمل مرة واحدةGC.SuppressFinalize(this): تم التنظيف، فتخط دالة الإنهاء| الطريقة | الشكل | الحكم |
|---|---|---|
| استدعاؤها بنفسك | r.Dispose(); في النهاية | لا يجري إذا رمي استثناء قبله |
| try / finally | finally { r?.Dispose(); } | ينفذ دائما؛ وتحمي ?. من فشل المنشئ |
| كتلة using | using (var r = ...) { ... } | يحرر عند القوس المغلق |
| تصريح using | using var r = ...; | يحرر عند نهاية النطاق المحيط |
using LogFile log4 = new LogFile("log.txt");
log4.Write(67);
Console.WriteLine("end of Main");LogFile: file opened
end of Main
LogFile: file closedالجزء 3
بايتات، وموضع، وقواعد فتح الملف
new FileStream(path, FileMode, FileAccess, FileShare): يجيب الوضع عن السؤالين.
| يمكنه الإنشاء | الملف غير موجود | الملف موجود |
|---|---|---|
Create | ينشئه | يفرغه (يكتب فوقه) |
CreateNew | ينشئه | يرمي IOException |
OpenOrCreate | ينشئه | يفتحه، والموضع 0 |
Append | ينشئه | يفتحه، والموضع عند النهاية (مع Write فقط) |
| يحتاج إلى الملف | الملف غير موجود | الملف موجود |
|---|---|---|
Open | يرمي FileNotFoundException | يفتحه، والموضع 0 |
Truncate | يرمي FileNotFoundException | يفتحه ويقتطعه إلى 0 بايت |
يحتوي test.txt على HELLO. افتحه باستخدام FileAccess.Write، واكتب a ثم b، ثم أغلقه. توقع الملف.
| FileMode | بعد الفتح مباشرة | الملف بعد كتابة ab |
|---|---|---|
Append | الموضع 5، والطول 5 | HELLOab |
Create | الموضع 0، والطول 0 | ab |
CreateNew | IOException | دون تغيير |
الملف نفسه، والبايتان نفساهما. والآن Open وOpenOrCreate وTruncate.
| FileMode | بعد الفتح مباشرة | الملف بعد كتابة ab |
|---|---|---|
Open | الموضع 0، والطول 5 | abLLO |
OpenOrCreate | الموضع 0، والطول 5 | abLLO |
Truncate | الموضع 0، والطول 0 | ab |
Read only : CanRead=True CanWrite=False CanSeek=True
Read write: CanRead=True CanWrite=True CanSeek=Truefs.WriteByte(65);
fs.WriteByte(66);Position=0 Length=0
Position=1 Length=1
Position=2 Length=2
File now holds: ABCanRead / CanWrite قيمة FileAccess؛ وقيمة CanSeek هي true مع الملفPosition من 0، مثل مؤشر الكتابة عند بداية الملفWriteByte بايتا واحدا عند Position وتقدمه بمقدار 1Length يزداديحتوي data.txt على HELLO. تفتح كل حالة تدفقها الخاص، ثم تفعل شيئا واحدا.
| فتح باستخدام | ثم |
|---|---|
Open، Write | fs.ReadByte() |
Open، Read | fs.WriteByte(65) |
Append، Read | لا شيء |
Append، Write | fs.Seek(0, SeekOrigin.Begin) |
ReadByte on a Write-only stream:
NotSupportedException
WriteByte on a Read-only stream:
NotSupportedException
Append with FileAccess.Read:
ArgumentException
Append, then Seek back to 0:
IOExceptionNone: لا يجوز لأحد غيرك فتح الملفRead: يجوز للآخرين فتحه للقراءةWrite: يجوز للآخرين فتحه للكتابةReadWrite: يجوز للآخرين القراءة والكتابةInheritable: يمكن لعملية فرعية أن ترث المقبضFileShare.Read: second reader opened, first byte = 72
FileShare.Read: a writer was refused (IOException)
FileShare.None: second reader was refused (IOException)قد تعيد Read بايتات أقل مما طلبت، لذا كرر حتى لا يبقى شيء؛ وتعيد 0 عند النهاية. يحتوي الملف على C# streams: توقع البايتات.
data = new byte[fs.Length];
int numBytesToRead = (int)fs.Length;
int numBytesRead = 0;
while (numBytesToRead > 0)
{
int n = fs.Read(data, numBytesRead, numBytesToRead);
if (n == 0) break; // end of the file
numBytesRead += n;
numBytesToRead -= n;
}Read 10 bytes:
67 35 32 115 116 114 101 97 109 115
copy.txt holds: C# streamsfs.Seek(offset, SeekOrigin.Begin); // or Current, or Endp: الموضع الجديد، o: الإزاحة التي تمررهاb تساوي 0 مع Begin، والموضع الحالي مع Current، والطول مع Endملف جديد فارغ. fs.Seek(20, SeekOrigin.Begin); fs.WriteByte(65); ثم اقرأ كل بايت بدءا من 0. توقع الطول والبايتات.
Position=21 Length=21
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 65 الجزء 4
حول البايتات إلى أسطر وقيم، أو اضغطها
تضيف Write وWriteLine النص، وتدفع Flush النص المخزن مؤقتا إلى الملف، وتفرغ Close ثم تغلق. توقع كل حجم.
var w = new StreamWriter(fs); // fs: note.txt
w.Write("Hello"); // size?
w.Flush(); // size?
w.WriteLine(" OS"); // size?
w.Close(); // size?After Write : file size = 0
After Flush : file size = 5
After WriteLine: file size = 5
After Close : file size = 10يحتوي lines.txt على Streams وand وDirectories. تنظر Peek دون أن تستهلك، وتستهلك Read حرفا واحدا، وReadLine سطرا واحدا (وnull عند النهاية).
Console.WriteLine("Peek: " + sr.Peek() + " = '" + (char)sr.Peek() + "'");
Console.WriteLine("Read: " + (char)sr.Read());
Console.WriteLine("Peek: " + (char)sr.Peek());
Console.WriteLine("ReadLine: " + sr.ReadLine());Peek: 83 = 'S'
Read: S
Peek: t
ReadLine: treamssr.BaseStream.Seek(0, SeekOrigin.Begin);
string str = sr.ReadLine();
while (str != null)
{
Console.WriteLine(str);
str = sr.ReadLine();
}1: Streams
2: and
3: Directories
ReadLine returned null after line 3Characters read: 25
File size: 25 bytesتخزن القيم بصيغتها الثنائية، لا نصا. توقع حجم الملف: int، وdouble، وbool، وdouble.
dataout = new BinaryWriter(
new FileStream("data", FileMode.Create));
dataout.Write(20); // int
dataout.Write(101.50); // double
dataout.Write(true); // bool
dataout.Write(12.2 * 15.5); // double
dataout.Close();File size: 21 bytes
First 4 bytes (the int 20): 20 0 0 0
Byte 12 (the bool true): 1| الدالة | ما تفعله |
|---|---|
File.WriteAllText / ReadAllText | تكتب / تقرأ ملفا كاملا نصا واحدا |
File.WriteAllLines / ReadAllLines | تكتب / تقرأ مصفوفة من الأسطر |
File.WriteAllBytes / ReadAllBytes | تكتب / تقرأ مصفوفة من البايتات |
File.Exists / File.Delete | تتحقق من وجود ملف / تحذفه |
File.Move | تنقل أو تعيد التسمية: لا توجد دالة Rename |
يغلف المزخرف الـFileStream وهو نفسه تدفق؛ وتعيد CompressionMode.Decompress البايتات. توقع الحجم على القرص.
using (FileStream fs = File.Create("data.bin"))
using (DeflateStream ds = new DeflateStream(fs, CompressionMode.Compress))
ds.Write(original, 0, original.Length); // 1000 bytes: ABCABC...Original bytes : 1000
data.bin on disk: 15 bytes
Bytes after decompress: 1000 (first 65, last 65)الجزء 5
إنشاء المجلدات وسرد محتواها وقياسها ونسخها والبحث فيها
Directory | DirectoryInfo | |
|---|---|---|
| النوع | صنف ساكن (static) | كائن واحد لكل مجلد |
| الاستدعاء | Directory.Exists(path) | new DirectoryInfo(path).Exists |
| يعطي | نصوصا (مسارات) | كائنات DirectoryInfo وFileInfo |
CreateDirectory، Move، DeleteGetDirectories، GetFiles، GetFileSystemEntriesGetCurrentDirectory، GetDirectoryRoot، GetLogicalDrives، GetCreationTime، GetLastWriteTimeConsole.WriteLine("Root: " + Directory.GetDirectoryRoot(curDir));
Console.WriteLine("Drives: " + string.Join(" ", Directory.GetLogicalDrives()));
File.WriteAllText("lab3/test/a.txt", "abc");
Directory.Delete("lab3/test"); // inside try / catch: predict!Root: D:\
Drives: C:\ D:\
Delete(test) failed: IOExceptionتبنيها MakeSampleTree() في كل برنامج من برامج المجلدات. والأحجام أطوال حقيقية للملفات.
site
about.txt 48 bytes
work.txt 13 bytes
images
logo.bin 300 bytes
wiki
home.txt 19 bytes
week1.txt 25 bytes
old
week0.txt 13 bytesabout.txt النص "Streams move bytes between a program and a file."week1.txt النص "Week 1: what is a stream?"Directory.GetFileSystemEntries("site", "w*");
Directory.GetFiles("site", "w*", SearchOption.AllDirectories);GetFileSystemEntries(site, w*):
site\wiki
site\work.txt
GetFiles(site, w*, AllDirectories):
site\work.txt
site\wiki\week1.txt
site\wiki\old\week0.txtFileInfo.Length حجم ملف واحد بالبايت. توقع حجم شجرة العينة، ثم حجم مجلدها الأعلى وحده (TopDirectoryOnly).
Name، Extension، FullName، Directory، وLength (بالبايت)CreationTime، LastAccessTime، LastWriteTimeCreate، AppendText، Delete، Open، OpenRead، CopyToforeach (FileInfo fi in dirInfo.GetFiles("*", SearchOption.AllDirectories))
size += fi.Length;The directory size: 418 bytes
Top level files only: 61 bytesتطبع DirectoryCopy("site", "site-2", true) كل مجلد تنشئه وكل ملف تنسخه. توقع الترتيب.
var dir = new DirectoryInfo(source);
DirectoryInfo[] dirs = dir.GetDirectories();
if (!Directory.Exists(dest))
Directory.CreateDirectory(dest);
foreach (FileInfo file in dir.GetFiles())
file.CopyTo(Path.Combine(dest, file.Name), false);
if (copySubDirs)
foreach (DirectoryInfo subdir in dirs)
DirectoryCopy(subdir.FullName,
Path.Combine(dest, subdir.Name), copySubDirs);create site-2
copy site-2\about.txt
copy site-2\work.txt
create site-2\images
copy site-2\images\logo.bin
create site-2\wiki
copy site-2\wiki\home.txt
copy site-2\wiki\week1.txt
create site-2\wiki\old
copy site-2\wiki\old\week0.txt
Copying finished
Files in site-2: 6الجزء 6
نحو 30 دقيقة: توقع أولا، ثم شغل البرنامج
نحو 6 دقائق
File.WriteAllText("data.txt", "STREAM");
using var fs = new FileStream("data.txt", FileMode.Open, FileAccess.ReadWrite);
fs.ReadByte(); fs.ReadByte();
fs.Seek(2, SeekOrigin.Current);
fs.WriteByte(33);
fs.Seek(-1, SeekOrigin.End);
fs.ReadByte(); fs.ReadByte();
fs.Seek(8, SeekOrigin.Begin);
fs.WriteByte(90);1) ReadByte() = 83, Position = 1
2) ReadByte() = 84, Position = 2
3) Seek(2, Current): Position = 4
4) WriteByte(33): Position = 5, Length = 6
5) Seek(-1, End): Position = 5
6) ReadByte() = 77, Position = 6
7) ReadByte() = -1, Position = 6
8) Seek(8, Begin), WriteByte(90): Position = 9, Length = 9
Bytes: 83 84 82 69 33 77 0 0 90نحو 5 دقائق
FileMode وأي FileAccess؟FileMode.CreateNew مرتين متتاليتين على new.txt. ماذا يحدث في كل مرة؟hello.txt على HELLO. افتحه باستخدام Open وWrite، ثم WriteByte((byte)'J'). ماذا يحتوي الملف؟FileMode.Truncate مع FileAccess.Read. ماذا يحدث، وماذا يحتوي الملف؟| الحالة | الإجابة |
|---|---|
| (a) | Append مع Write: 3 تشغيلات تعطي 3 أسطر |
| (b) | ينشأ الملف، ثم IOException: الملف موجود |
| (c) | JELLO: لا يفرغ Open البيانات، ويكتب J فوق H |
| (d) | ArgumentException: يحتاج Truncate إلى صلاحية الكتابة؛ ويبقى JELLO |
نحو 4 دقائق
bw.Write(7);
bw.Write(true);
bw.Write(3.5);
bw.Write(false);
bw.Write(1000);Size: 18 bytes
7 True 3.5 False 1000
Last 4 bytes: 232 3 0 0نحو 5 دقائق
Windows وLinux وmacOS وFreeBSD وAndroid في os.txt باستخدام StreamWriter، كل اسم في سطرStreamReader.ReadLine حتى تعيد nullstring line = sr.ReadLine();
while (line != null)
{
count++;
if (line.Length > longest.Length)
longest = line;
line = sr.ReadLine();
}Lines: 5
Longest: Windows (7 characters)
File size: 41 bytesنحو 6 دقائق
PrintTree(DirectoryInfo dir, string indent)/، ثم ملفاته بأحجامها، ثم استدع الدالة لكل مجلد فرعي بإزاحة أعمقsite: اطبع المجموع، ثم حجم site/wiki وحدهstatic long PrintTree(DirectoryInfo dir, string indent)
{
long total = 0;
Console.WriteLine(indent + dir.Name + "/");
foreach (FileInfo f in dir.GetFiles())
{
Console.WriteLine(indent + " " + f.Name
+ " (" + f.Length + ")");
total += f.Length;
}
foreach (DirectoryInfo sub in dir.GetDirectories())
total += PrintTree(sub, indent + " ");
return total;
}site/
about.txt (48)
work.txt (13)
images/
logo.bin (300)
wiki/
home.txt (19)
week1.txt (25)
old/
week0.txt (13)
Total: 418 bytes
wiki: 57 bytesنحو 5 دقائق
الدالة DirSearch("site") من المصدر، تبحث عن stream
foreach (var directory in Directory.GetDirectories(sDir))
{
foreach (var filename in Directory.GetFiles(directory))
{
// read it, lower-case it,
// add it if it contains "stream"
}
DirSearch(directory);
}DirSearch؟FileSearch(string sDir): ابحث في ملفات sDir أولا، ثم استدع الدالة لكل مجلد فرعيFileSearch؟foreach (var filename in Directory.GetFiles(sDir))
using (var sr = new StreamReader(filename))
if (sr.ReadToEnd().ToLower().Contains(SearchText))
FilesFound.Add(filename);
foreach (var directory in Directory.GetDirectories(sDir))
FileSearch(directory);DirSearch: files containing the word stream
site\wiki\week1.txt
FileSearch: files containing the word stream
site\about.txt
site\wiki\week1.txtIDisposable يجب تحريره: والأفضل استخدام usingFileMode عن السؤالين "غير موجود؟" و"البيانات القديمة؟"؛ ويحد FileAccess مما يجوز للتدفق فعله؛ ويكتب Open فوق البيانات في مكانهاFlush أو CloseMahmoud Abas|التدفقات وعمليات المجلدات بلغة C#