2019.04.19 读书笔记 比较File.OpenRead()和File.ReadAllBytes()的差异
最近涉及到流的获取与转化,终于要还流的债了。
百度了一下,看到这样的两条回复,于是好奇心,决定看看两种写法的源码差异。
先来看看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()的差异的更多相关文章
- 2019.04.18 读书笔记 深入string
整个.net中,最特殊的就是string类型了,它有着引用类型的特性,又有着值类型的操作方式,最特殊的是,它还有字符串池,一个字符串只会有一个实例(等下就推翻!). 鉴于之前的<==与Equal ...
- 2019.04.17 读书笔记 checked与unchecked
在普通的编程中,我们是很容易去分析数据的大小,然后给出合理的类型,但是在很多数据库的累计中,缺存在很多隐患,特别是研发时,数据量小,求和也不会溢出,当程序运行几年后,再来一次大求和,隐形的BUG就出来 ...
- 2019.03.19 读书笔记 string与stringbuilder的性能
1 string与stringbuilder 并不是stringbuilder任何时候都在性能上占优势,在少量(大约个位数)的字符串时,并不比普通string操作快. string慢的原因不是stri ...
- 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 ...
- 2019.03.29 读书笔记 关于params与可选参数
void Method1(string str, object a){} void Method2(string str, object a,object b) { } void Method3(st ...
- 2019.03.29 读书笔记 关于override与new
差异:override:覆盖父类分方法,new 隐藏父类方法. 共同:都不能改变父类自身方法. public class Test { public string Name { get; set; } ...
- 2019.03.28 读书笔记 关于lock
多线程就离不开lock,lock的本质是一个语法糖,采用了监视器Monitor. lock的参数,错误方式有很多种,只需要记住一种:private static readonly object loc ...
- 2019.03.28 读书笔记 关于try catch
try catch 在不异常的时候不损耗性能,耗损性能的是throw ex,所以在非异常是,不要滥用throw,特别是很多代码习惯:if(age<0) throw new Exception(& ...
- 2019.03.27 读书笔记 关于GC垃圾回收
在介绍GC前,有必要对.net中CLR管理内存区域做简要介绍: 1. 堆栈:用于分配值类型实例.堆栈主要操作系统管理,而不受垃圾收集器的控制,当值类型实例所在方法结束时,其存储单位自动释放.栈的执行效 ...
随机推荐
- mybatis 输入、输出映射
一.输入映射 mapper.xml的参数只有一个.可以传参数,基本简单类型,hashmap和javabean (一).Javabean的方法. 需求:通过小说名和作者模糊找书. 1.定义Javabea ...
- linux 用户和组
每个用户拥有一个UID,操作系统实际使用的是用户ID,而非用户名 每个用户属于一个主组,而且属于一个或多个附属组 每个组有一个GroupID 每个进程以一个用户身份运行,并受该用户可访问的资源限制 每 ...
- nginx中级应用
1.安装监控模块 Nginx中的stub_status模块主要用于查看Nginx的一些状态信息. 本模块默认是不会编译进Nginx的,如果你要使用该模块,则要在编译安装Nginx时指定: . /con ...
- TSQL--SORT MERGE JOIN
算法:对两表排序,然后对两表依次扫描,找到符合条件的结果集 sort(T1); seort(T2); int k=0;--for T1 index int m=0;--for T2 index whi ...
- 关于人脸识别引擎FaceRecognitionDotNet的实例
根据我上篇文章的分享,我提到了FaceRecognitionDotNet,它是python语言开发的一个项目face_recognition移植.结果真是有喜有忧,喜的是很多去关注了,进行了下载,我看 ...
- WPF 控件库——仿制Windows10的进度条
WPF 控件库系列博文地址: WPF 控件库——仿制Chrome的ColorPicker WPF 控件库——仿制Windows10的进度条 WPF 控件库——轮播控件 WPF 控件库——带有惯性的Sc ...
- BT Tracker的原理及.Net Core简单实现Tracker Server
最近很忙,自上次Blog被盗 帖子全部丢失后也很少时间更新Blog了,闲暇在国外站点查阅资料时正好看到一些Tracker 的协议资料,也就今天记录并实践了下,再次分享给大家希望可以帮到需要的小伙伴. ...
- Flash Builder 4.6/4.7 注释以及字体大小修改
①修改字体颜色.粗体.斜体.下划线 英文版:windows-preferences-flex-editors-syntex coloring-ActionScript-Comment 汉化版:窗口—首 ...
- 二十四、MongoDB数据库的使用
首先按照上一篇文章的介绍,启动并连接数据库 然后我们开始学习如何使用MongoDB数据库: 1.创建数据库 第一步,在cmd窗口执行: use dbname dbname是你打算要创建的数据库名称 执 ...
- linux命令之系统管理命令(下)
1.chkconfig:管理开机服务 该命令为linux系统中的系统服务管理工具,可以查询和更新不同的运行等级下系统服务的启动状态. 选项 说明 --list(常用) 显示不同运行级别下服务的启动状态 ...