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. 堆栈:用于分配值类型实例.堆栈主要操作系统管理,而不受垃圾收集器的控制,当值类型实例所在方法结束时,其存储单位自动释放.栈的执行效 ...
随机推荐
- 32 取一个整数a从右端开始的4-7位
题目:取一个整数a从右端开始的4-7位 public class _032FetchDigit { public static void main(String[] args) { fetchDigi ...
- javascript总结30 :DOM事件
事件: 1 在js中可以说一整套事件能完成一个功能: 事件的定义:当什么时候执行什么事: 使用事件的基本结构:事件源+事件类型=执行的指令 2 事件三要素:事件源 事件类型, 驱动程序(匿名函数). ...
- SPARK_sql加载,hive以及jdbc使用
sql加载 格式 或者下面这种直接json加载 或者下面这种spark的text加载 以及rdd的加载 上述记得配置文件加入.mastrt("local")或者spark://m ...
- 基于 Web 的数据挖掘--自动抽取用 HTML、XML 和 Java 编写的信息
简介: 不可否认,万维网是到目前为止世界上最丰富和最密集的信息来源.但是,它的结构使它很难用系统的方法来利用信息.本文描述的方法和工具将使那些熟悉 Web 最常用技术的开发人员能快速而便捷地获取他们所 ...
- 洛谷 P2146 [NOI2015]软件包管理器 (树链剖分模板题)
题目描述 Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖(即下载安装这个 ...
- 16、Semantic-UI之模态窗口
16.1 定义模态窗口 示例:定义基础的模态窗口 <!DOCTYPE html> <html lang="en"> <head> <met ...
- Win8共享wifi热点设置
Win8共享wifi热点如何设置?大家都知道win7系统可以实现wifi热点共享,那么win8应该也能实现wifi热点共享,那么如何设置win8不需要任何软件只需要对电脑进行设置就可以共享无线上网. ...
- 基于.net standard 的动态编译实现
在前文[基于.net core 微服务的另类实现]结尾处,提到了如何方便自动的生成微服务的客户端代理,使对于调用方透明,同时将枯燥的东西使用框架集成,以提高使用便捷性.在尝试了基于 Emit 中间语言 ...
- oracle goldengate的两种用法
此文已由作者赵欣授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 自从oracle收购来了goldengate这款产品并以后对它做了一系列改进后,有非常多的用户使用它做数据迁移 ...
- 在macbookpro上开启ssh服务