code
FileStream fs=new FileStream(...);
Int32 bsRead=fs.Read(...);
- 首先通过构造一个FileStream对象,实现打开指定的磁盘文件
- 然后通过调用Read方法来读文件内容
- 调用Read方法时,首先线程从托管代码转移到了本地用户级代码,通过内部调用Win32的ReadFile函数实现读文件
- Win32的ReadFile会分配一个名叫I/O请求包(IRP)的数据结构,这个IRP结构初始化时会包含一个指向文件的句柄,一个要读取的文件偏移量(从文件的哪里开始读),一个要读的字节内容(Byte[]),以及要传送的字节数,还有一些其他不太重要的东西。
- 随后Win32的ReadFile通过线程从用户级代码转入内核级代码,传递IRP的数据到了内核。
- 从IRP中的设备句柄号,windows内核知道需要请求哪个硬件设备的I/O操作,然后Windows派发这个IRP到对应的设备驱动的IRP队列中去。每个设备驱动维护它们自己的IRP队列,这些IRP队列包含了所有在运行进程的请求。
- 到指定的IRP要处理时,设备驱动器传递IRP信息到实际与其关联的硬件设备的电路板上。现在硬件设备就开始执行这个I/O请求操作了。
- 当硬件设备处理I/O操作时,你的这个与其相对应的线程就会出现等待(Windows会休眠该线程,为了避免浪费CPU时间,但该线程还是占用了部分内存)。与其对应的UI界面也可能会因为被阻塞而没有响应(如果在托管代码做了异步处理,则不会阻塞)。
- 当硬件设备完成I/O操作后,Windows将立即唤醒对应的线程,将其调度进CPU进行操作,并让它从内核模式返回到用户模式,再返回到托管代码。
- 此时FileStream的Read方法返回了一个指示了实际读取字节数长度的Int32值
所以面对I/O密集型的操作,我们应该采取一些多线程实现异步I/O请求。如使用ReadAsync等。