最近涉及到流的获取与转化,终于要还流的债了。

百度了一下,看到这样的两条回复,于是好奇心,决定看看两种写法的源码差异。

先来看看OpenRead()

public static FileStream OpenRead(string path) =>
new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read); //构造函数又调用了其他构造函数,继续深入
[SecuritySafeCritical]
public FileStream(string path, FileMode mode, FileAccess access, FileShare share) : this(path, mode, access, share, 0x1000, FileOptions.None, Path.GetFileName(path), false)
{
}
//调用了Init 初始化
[SecurityCritical]
internal FileStream(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options, string msgPath, bool bFromProxy)
{
Win32Native.SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(share);
this.Init(path, mode, access, , false, share, bufferSize, options, secAttrs, msgPath, bFromProxy, false, false);
} //读取数据到流中,过程就没什么可以看的了
[SecuritySafeCritical]
private unsafe void Init(string path, FileMode mode, FileAccess access, int rights, bool useRights, FileShare share, int bufferSize, FileOptions options, Win32Native.SECURITY_ATTRIBUTES secAttrs, string msgPath, bool bFromProxy, bool useLongPath, bool checkHost)
{
int num;
if (path == null)
{
throw new ArgumentNullException("path", Environment.GetResourceString("ArgumentNull_Path"));
}
if (path.Length == )
{
throw new ArgumentException(Environment.GetResourceString("Argument_EmptyPath"));
}
FileSystemRights rights2 = (FileSystemRights) rights;
this._fileName = msgPath;
this._exposedHandle = false;
FileShare share2 = share & ~FileShare.Inheritable;
string paramName = null;
if ((mode < FileMode.CreateNew) || (mode > FileMode.Append))
{
paramName = "mode";
}
else if (!useRights && ((access < FileAccess.Read) || (access > FileAccess.ReadWrite)))
{
paramName = "access";
}
else if (useRights && ((rights2 < FileSystemRights.ListDirectory) || (rights2 > FileSystemRights.FullControl)))
{
paramName = "rights";
}
else if ((share2 < FileShare.None) || (share2 > (FileShare.Delete | FileShare.ReadWrite)))
{
paramName = "share";
}
if (paramName != null)
{
throw new ArgumentOutOfRangeException(paramName, Environment.GetResourceString("ArgumentOutOfRange_Enum"));
}
if ((options != FileOptions.None) && ((options & 0x3ffbfff) != FileOptions.None))
{
throw new ArgumentOutOfRangeException("options", Environment.GetResourceString("ArgumentOutOfRange_Enum"));
}
if (bufferSize <= )
{
throw new ArgumentOutOfRangeException("bufferSize", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
}
if (((!useRights && ((access & FileAccess.Write) == )) || (useRights && ((rights2 & FileSystemRights.Write) == ))) && (((mode == FileMode.Truncate) || (mode == FileMode.CreateNew)) || ((mode == FileMode.Create) || (mode == FileMode.Append))))
{
if (!useRights)
{
object[] objArray1 = new object[] { mode, access };
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFileMode&AccessCombo", objArray1));
}
object[] values = new object[] { mode, rights2 };
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFileMode&RightsCombo", values));
}
if (useRights && (mode == FileMode.Truncate))
{
if (rights2 != FileSystemRights.Write)
{
object[] objArray3 = new object[] { mode, rights2 };
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFileModeTruncate&RightsCombo", objArray3));
}
useRights = false;
access = FileAccess.Write;
}
if (!useRights)
{
num = (access == FileAccess.Read) ? - : ((access == FileAccess.Write) ? 0x40000000 : -);
}
else
{
num = rights;
}
int maxPathLength = useLongPath ? 0x7fff : (AppContextSwitches.BlockLongPaths ? : 0x7fff);
string fullPath = Path.NormalizePath(path, true, maxPathLength);
this._fileName = fullPath;
if ((!CodeAccessSecurityEngine.QuickCheckForAllDemands() || AppContextSwitches.UseLegacyPathHandling) && fullPath.StartsWith(@"\\.\", StringComparison.Ordinal))
{
throw new ArgumentException(Environment.GetResourceString("Arg_DevicesNotSupported"));
}
bool flag = false;
if ((!useRights && ((access & FileAccess.Read) != )) || (useRights && ((rights2 & FileSystemRights.ReadAndExecute) != )))
{
if (mode == FileMode.Append)
{
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidAppendMode"));
}
flag = true;
}
if (CodeAccessSecurityEngine.QuickCheckForAllDemands())
{
FileIOPermission.EmulateFileIOPermissionChecks(fullPath);
}
else
{
FileIOPermissionAccess noAccess = FileIOPermissionAccess.NoAccess;
if (flag)
{
noAccess |= FileIOPermissionAccess.Read;
}
if (((!useRights && ((access & FileAccess.Write) != )) || (useRights && ((rights2 & (FileSystemRights.TakeOwnership | FileSystemRights.ChangePermissions | FileSystemRights.Delete | FileSystemRights.Write | FileSystemRights.DeleteSubdirectoriesAndFiles)) != ))) || ((useRights && ((rights2 & FileSystemRights.Synchronize) != )) && (mode == FileMode.OpenOrCreate)))
{
if (mode == FileMode.Append)
{
noAccess |= FileIOPermissionAccess.Append;
}
else
{
noAccess |= FileIOPermissionAccess.Write;
}
}
AccessControlActions control = ((secAttrs != null) && (secAttrs.pSecurityDescriptor != null)) ? AccessControlActions.Change : AccessControlActions.None;
string[] fullPathList = new string[] { fullPath };
FileIOPermission.QuickDemand(noAccess, control, fullPathList, false, false);
}
share &= ~FileShare.Inheritable;
bool flag2 = mode == FileMode.Append;
if (mode == FileMode.Append)
{
mode = FileMode.OpenOrCreate;
}
if ((options & FileOptions.Asynchronous) != FileOptions.None)
{
this._isAsync = true;
}
else
{
options &= ~FileOptions.Asynchronous;
}
int dwFlagsAndAttributes = (int) options;
dwFlagsAndAttributes |= 0x100000;
int newMode = Win32Native.SetErrorMode();
try
{
string str3 = fullPath;
if (useLongPath)
{
str3 = Path.AddLongPathPrefix(str3);
}
this._handle = Win32Native.SafeCreateFile(str3, num, share, secAttrs, mode, dwFlagsAndAttributes, IntPtr.Zero);
if (this._handle.IsInvalid)
{
int errorCode = Marshal.GetLastWin32Error();
if ((errorCode == ) && fullPath.Equals(Directory.InternalGetDirectoryRoot(fullPath)))
{
errorCode = ;
}
bool flag4 = false;
if (!bFromProxy)
{
try
{
FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, this._fileName, false, false);
flag4 = true;
}
catch (SecurityException)
{
}
}
if (flag4)
{
__Error.WinIOError(errorCode, this._fileName);
}
else
{
__Error.WinIOError(errorCode, msgPath);
}
}
}
finally
{
Win32Native.SetErrorMode(newMode);
}
if (Win32Native.GetFileType(this._handle) != )
{
this._handle.Close();
throw new NotSupportedException(Environment.GetResourceString("NotSupported_FileStreamOnNonFiles"));
}
if (this._isAsync)
{
bool flag5 = false;
new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert();
try
{
flag5 = ThreadPool.BindHandle(this._handle);
}
finally
{
CodeAccessPermission.RevertAssert();
if (!flag5)
{
this._handle.Close();
}
}
if (!flag5)
{
throw new IOException(Environment.GetResourceString("IO.IO_BindHandleFailed"));
}
}
if (!useRights)
{
this._canRead = (access & FileAccess.Read) > ;
this._canWrite = (access & FileAccess.Write) > ;
}
else
{
this._canRead = (rights2 & FileSystemRights.ListDirectory) > ;
this._canWrite = ((rights2 & FileSystemRights.CreateFiles) != ) || ((rights2 & FileSystemRights.AppendData) > );
}
this._canSeek = true;
this._isPipe = false;
this._pos = 0L;
this._bufferSize = bufferSize;
this._readPos = ;
this._readLen = ;
this._writePos = ;
if (flag2)
{
this._appendStart = this.SeekCore(0L, SeekOrigin.End);
}
else
{
this._appendStart = -1L;
}
}

从上面的源码可以看出,OpenRead会把无论多大的文件都读取到FileStream中,能有多大呢?FileStream.Length可是long型的,就是2的63次方了,2的40次方是1T,大约就是8MT吧,我们的常用硬盘是没这么大的了,可以说能读出天荒地老了。那么图片中的第一中写法,读取没错,但是转换int就留下了隐患,int的最大限制是2G,如果文件超过2G,那么转换就会被截取,导致读到data里的数据就不完整了。所以一定不要偷懒,由于FileStream.Read的参数是int型的,一定要判断流的长度,如果超过了int最大值,要循环read。

再来看看File.ReadAllBytes(),上源码:

[SecurityCritical]
private static byte[] InternalReadAllBytes(string path, bool checkHost)
{
byte[] buffer;
using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 0x1000, FileOptions.None, Path.GetFileName(path), false, false, checkHost))//这里也是和OpenRead一样,把文件全部读取进来了
{
int offset = ;
long length = stream.Length;
if (length > 0x7fffffffL)//这里才是关键,对长度做了一个判断,如果超过了2G,就抛异常了,所以决定了这个方法的文件不能超过2G
{
throw new IOException(Environment.GetResourceString("IO.IO_FileTooLong2GB"));
}
int count = (int) length;
buffer = new byte[count];
while (count > )
{
int num4 = stream.Read(buffer, offset, count);
if (num4 == )
{
__Error.EndOfFile();
}
offset += num4;
count -= num4;
}
}
return buffer;
}

第二种写法会导致在读取文件超过2G后抛出异常,所以使用时要确定文件的大小,否则就用OpenRead()。

所以图中两种写法都可能存在隐患的BUG。

当然,在确定了不可能超过2G的情况下,还是可以自由使用的。

2019.04.19 读书笔记 比较File.OpenRead()和File.ReadAllBytes()的差异的更多相关文章

  1. 2019.04.18 读书笔记 深入string

    整个.net中,最特殊的就是string类型了,它有着引用类型的特性,又有着值类型的操作方式,最特殊的是,它还有字符串池,一个字符串只会有一个实例(等下就推翻!). 鉴于之前的<==与Equal ...

  2. 2019.04.17 读书笔记 checked与unchecked

    在普通的编程中,我们是很容易去分析数据的大小,然后给出合理的类型,但是在很多数据库的累计中,缺存在很多隐患,特别是研发时,数据量小,求和也不会溢出,当程序运行几年后,再来一次大求和,隐形的BUG就出来 ...

  3. 2019.03.19 读书笔记 string与stringbuilder的性能

    1 string与stringbuilder 并不是stringbuilder任何时候都在性能上占优势,在少量(大约个位数)的字符串时,并不比普通string操作快. string慢的原因不是stri ...

  4. RH253读书笔记(5)-Lab 5 Network File Sharing Services

    Lab 5 Network File Sharing Services Goal: Share file or printer resources with FTP, NFS and Samba Se ...

  5. 2019.03.29 读书笔记 关于params与可选参数

    void Method1(string str, object a){} void Method2(string str, object a,object b) { } void Method3(st ...

  6. 2019.03.29 读书笔记 关于override与new

    差异:override:覆盖父类分方法,new 隐藏父类方法. 共同:都不能改变父类自身方法. public class Test { public string Name { get; set; } ...

  7. 2019.03.28 读书笔记 关于lock

    多线程就离不开lock,lock的本质是一个语法糖,采用了监视器Monitor. lock的参数,错误方式有很多种,只需要记住一种:private static readonly object loc ...

  8. 2019.03.28 读书笔记 关于try catch

    try catch 在不异常的时候不损耗性能,耗损性能的是throw ex,所以在非异常是,不要滥用throw,特别是很多代码习惯:if(age<0) throw new Exception(& ...

  9. 2019.03.27 读书笔记 关于GC垃圾回收

    在介绍GC前,有必要对.net中CLR管理内存区域做简要介绍: 1. 堆栈:用于分配值类型实例.堆栈主要操作系统管理,而不受垃圾收集器的控制,当值类型实例所在方法结束时,其存储单位自动释放.栈的执行效 ...

随机推荐

  1. Swift & Objc 在同一个项目中的使用

    在WWDC大会中发布了Swift让人眼前一亮.终于加了很多的现代编程语言该有的东西.很早年以前玩C#3.0+的时候这些差不多类似的 已经用的烂熟的东西终于一点一点的在看Swift Programmin ...

  2. 编写高质量代码改善C#程序的157个建议——建议114:MD5不再安全

    建议114:MD5不再安全 MD5不再安全不是就算法本身而言的.如果从可逆性的角度出发,MD5值不存在被破解的可能性. MD5被广泛应用于密码验证和消息完整性验证.假设新注册一个用户,当注册用户的密码 ...

  3. 9.29学习的js基础

    js基础 1.三种js引入方式    a).<input type="button" value="点击事件" onClick="documen ...

  4. 检测远程主机上的某个端口是否开启——telnet命令

    要测试远程主机上的某个端口是否开启,无需使用太复杂的工作,windows下就自带了工具,那就是telnet.ping命令是不能检测端口,只能检测你和相应IP是否能连通. 1 安装telnet.win7 ...

  5. 深入理解java虚拟机(十一) 方法调用-解析调用与分派调用

    方法调用过程是指确定被调用方法的版本(即调用哪一个方法),并不包括方法执行过程.我们知道,Class 文件的编译过程中并不包括传统编译中的连接步骤,一切方法调用在 Class 文件调用里面存储的都只是 ...

  6. docker+selenium Grid搭建自动化分布式测试环境

    自动化测试需要考虑到兼容性的时候,之前的做法是每个执行机上安装不同版本的浏览器,实际上这样做会很浪费硬件资源,现在有了docker容器化技术,让一切变得简单. 工具清单: 语言:python 2.7 ...

  7. NET分页实现及代码

    最近在写一个关于NET的框架,写到后面果不其然的就遇到了分页,自己看了很多关于分页的并自己结合写了一个,晒出来和大家分享一下,第一次写博客望大家多多提意见啦... cs文件分页代码: Paging p ...

  8. Android 增量更新研究

    Android 增量更新实例(Smart App Updates) http://blog.csdn.net/duguang77/article/details/17676797 Android AP ...

  9. 《Beginning Java 7》 - 9 - Nested Types 嵌套类型

    嵌套类分为四种: static member class 静态成员类 nonstatic member class 非静态成员类 anonymous class 匿名类 local class 局部类 ...

  10. OI网络流 简单学习笔记

    持续更新! 基本上只是整理了一下框架,具体的学习给出了个人认为比较好的博客的链接. ..怎么说呢,最基础的模板我就我不说了吧qwq,具体可以参考一下这位大佬写的博客:最大流,最小割,费用流 费用流 跑 ...