时间:2021年04月25日 | 作者 : aaronyang | 分类 : .NET CORE | 浏览: 593次 | 评论 0 人
此节开始,使用vs2019
控制台讲解 处理文件、流、序列化
路径在 不同操作系统路径不同的
using System; using static System.Console; using static System.IO.Directory; using static System.IO.Path; using static System.Environment; namespace WorkingWithFileSystems { class Program { static void Main(string[] args) { WriteLine("{0,-33}{1}","Path.PathSeparator",PathSeparator); WriteLine("{0,-33}{1}", "Path.DirectorySeparatorChar", DirectorySeparatorChar); WriteLine("{0,-33}{1}", "Directory.GetCurrentDirectory()", GetCurrentDirectory()); WriteLine("{0,-33}{1}", "Environment.CurrentDirectory", CurrentDirectory); WriteLine("{0,-33}{1}", "Environment.SystemDirectory", SystemDirectory); WriteLine("{0,-33}{1}", "Path.GetTempPath()", GetTempPath()); WriteLine("特殊目录"); WriteLine("{0,-33}{1}", ".System", GetFolderPath(SpecialFolder.System)); WriteLine("{0,-33}{1}", ".ApplicationData", GetFolderPath(SpecialFolder.ApplicationData)); WriteLine("{0,-33}{1}", ".MyDocuments", GetFolderPath(SpecialFolder.MyDocuments)); WriteLine("{0,-33}{1}", ".Personal", GetFolderPath(SpecialFolder.Personal)); Console.ReadLine(); } } }
Environment成员很多
Windows使用反斜杠作为目录分隔符,macOS和Linux使用正斜杠
WriteLine("{0,-30} | {1,-10} | {2,-7} | {3,18} | {4,18}","名称","类型","Format","大小","可用大小"); foreach (DriveInfo item in DriveInfo.GetDrives()) { if (item.IsReady) { WriteLine("{0,-30} | {1,-10} | {2,-7} | {3,18} | {4,18}", item.Name, item.DriveType,item.DriveFormat, item.TotalSize, item.AvailableFreeSpace); } else { WriteLine("{0,-30} | {1,-10} ", item.Name, item.DriveType); } }
using System; using static System.Console; using static System.IO.Directory; using static System.IO.Path; using static System.Environment; using System.IO; namespace WorkingWithFileSystems { class Program { static void Main(string[] args) { var newfolderRoot = Combine(GetFolderPath(SpecialFolder.Personal), "CoreCode"); var newfolder = Combine(newfolderRoot, "Chapter09","NewFolder"); if (!Directory.Exists(newfolder)) { CreateDirectory(newfolder); } Delete(newfolderRoot, recursive: true); Console.ReadLine(); } } }
var dir = Combine(GetFolderPath(SpecialFolder.Personal), "Code/Chapter09/OutputFiles"); CreateDirectory(dir); var textfile = Combine(dir, "Dummy.txt"); var backupfile = Combine(dir, "Dummy.bak"); WriteLine($"写{textfile}"); if (File.Exists(textfile)) { File.Delete(textfile); } using (StreamWriter tw=File.CreateText(textfile)) { tw.WriteLine("Hello Ay"); } //备份 File.Copy(textfile, backupfile, true); WriteLine($"bak文件是否存在:{File.Exists(backupfile)}"); //删除原来的文件 if (File.Exists(textfile)) { File.Delete(textfile); } //打开备份文件 using (StreamReader dr = File.OpenText(backupfile)) { WriteLine(dr.ReadToEnd()); }
Console.WriteLine($"文件夹名称:{GetDirectoryName(textfile)}"); Console.WriteLine($"文件名称:{GetFileName(textfile)}"); Console.WriteLine($"文件名无后缀:{GetFileNameWithoutExtension(textfile)}"); Console.WriteLine($"文件后缀:{GetExtension(textfile)}"); Console.WriteLine($"随机文件名:{GetRandomFileName()}"); Console.WriteLine($"临时文件名:{GetTempFileName()}");
GetRandomFileName 方法创建零字节的文件并返回文件名
GetTempFileName 方法只返回文件名而不会创建文件
FileInfo DirectoryInfo
var info = new FileInfo(backupfile); Console.WriteLine($"{info.Length} {info.LastAccessTime} {info.IsReadOnly}");
不同操作系统中字节数可能不同
FileOpen方法有个参数
FileMode 控制要对文件做什么,比如CreateNew,OpenOrCreate或Truncate
FileAccess 控制需要的访问级别,比如ReadWrite
FileShare 控制文件上的锁,从而允许其他进程以指定的访问级别访问,比如Read。
可以打开文件从文件中读取内容,并允许其他进程读取文件
FileStream file = File.Open(backupfile, FileMode.Open, FileAccess.Read, FileShare.Read); //FileAttributes:检查FileSystemInfo派生类型Attribute属性值,例如Archive和Encrypted等,还可以检查文件或者目录的特性,如下所示: var bakfileInfo = new FileInfo(backupfile); WriteLine("文件是否压缩?{0}",bakfileInfo.Attributes.HasFlag(FileAttributes.Compressed));
====================www.ayjs.net 杨洋 wpfui.com ayui ay aaronyang=======请不要转载谢谢了。=========
Stream抽象类
派生类: MemoryStream BufferedStream GZipStream SslStream
所有流实现了IDisposable接口
Stream常用
CanRead CanWrite 是否可以读写流
Length Position 确定总字节数和流中当前的位置
Dispose() 关闭释放流
Flush() 如果流有缓冲区,就将缓冲区中的字节写入流并清除缓冲区
Read() ReadAsync() 将指定数量的字节从流中读取到字节数组中,并向前推进位置
ReadByte() 从流中读取下一个字节,并推进位置
Seek() 将位置移动到指定的位置(前提是CanSeek为true)
Write() WriteAsync() 将字节组的内容写入流
WriteByte() 将一个字节写入流
System.IO.FileStream 字节存储在文件系统
System.IO.MemoryStream 字节存储在当前进程的内存中
System.Net.Sockets.NetworkStream 将字节存储在网络位置
System.Security.Cryptography.CryptoStream 对流进行加密和解密
System.IO.Compression.GzipStream DeflateStream 压缩和解压流
System.Net.Security.AuthenticatedStream 跨流发送凭据
常用辅助类
System.IO StreamReader 从底层流读取文本
System.IO StreamWriter 以文本的形式写入底层流
System.IO BinaryReader 从流中读取.NET类型,例如ReadDecimal 从底层流读取后面的16字节,ReadInt32 读取后面4字节
System.IO BinaryWriter 作为.NET类型写入流,带有decimal参数的write方法向底层流写入16字节, 带有int的写入4字节
System.Xml XmlReader 以XML的形式从底层流读取数据
System.Xml XmlWriter 以XML的形式写入底层流
string textFile = Combine(CurrentDirectory, "stream.txt"); using (StreamWriter text = File.CreateText(textFile)) { text.WriteLine("AY"); text.WriteLine("2021"); text.WriteLine("合肥"); } Console.WriteLine(File.ReadAllText(textFile));
写入Xml流
string xmlFile = Combine(CurrentDirectory, "stream.xml"); using (FileStream xmlFileStream = File.Create(xmlFile)) { using (XmlWriter xml=XmlWriter.Create(xmlFileStream,new XmlWriterSettings { Indent = true })) { xml.WriteStartDocument(); xml.WriteStartElement("infos"); xml.WriteElementString("info", "AY"); xml.WriteElementString("info", "2021"); xml.WriteElementString("info", "合肥"); xml.WriteEndDocument(); } } Console.WriteLine(File.ReadAllText(xmlFile));
当打开文件进行读写,使用.NET之外的资源,这些资源又称为非托管资源,必须在处理完之后释放。可以在finally块中调用Dispose方法。
string xmlFile = Combine(CurrentDirectory, "stream.xml"); FileStream xmlFileStream = null; XmlWriter xml = null; try { using (xmlFileStream = File.Create(xmlFile)) { using (xml = XmlWriter.Create(xmlFileStream, new XmlWriterSettings { Indent = true })) { xml.WriteStartDocument(); xml.WriteStartElement("infos"); xml.WriteElementString("info", "AY"); xml.WriteElementString("info", "2021"); xml.WriteElementString("info", "合肥"); xml.WriteEndDocument(); } } Console.WriteLine(File.ReadAllText(xmlFile)); } catch (Exception ex) { Console.WriteLine($"{ex.GetType()} {ex.Message}"); } finally { xmlFileStream?.Dispose(); xml?.Dispose(); }
效果同上
xml占用空间,可以使用一种名为GZIP的常见压缩算法压缩XML
using System.IO.Compression;
string gzipFile = Combine(CurrentDirectory, "streams.gzip"); FileStream fs = File.Create(gzipFile); using (GZipStream compressor = new GZipStream(fs, CompressionMode.Compress)) { using (XmlWriter xml = XmlWriter.Create(compressor)) { xml.WriteStartDocument(); xml.WriteStartElement("infos"); xml.WriteElementString("info", "AY"); xml.WriteElementString("info", "2021"); xml.WriteElementString("info", "合肥"); xml.WriteEndDocument(); } } //输出压缩的文件 WriteLine("{0} 包含 {1:N0} 字节",gzipFile,new FileInfo(gzipFile).Len gth); WriteLine("压缩的内容"); WriteLine(File.ReadAllText(gzipFile)); WriteLine("读取压缩的内容"); fs = File.Open(gzipFile,FileMode.Open); using (GZipStream decom=new GZipStream(fs,CompressionMode.Decompress)) { using (XmlReader xr=XmlReader.Create(decom)) { while (xr.Read()) { if((xr.NodeType==XmlNodeType.Element) && xr.Name == "info") { xr.Read(); WriteLine(xr.Value); } } } }
102个字节
NC2.1引入了Brotli算法,类似于Deflate和GZIP,但是输出密度大20%左右
Brotli最初发布于2015年,用于网络字体的离线压缩。Google软件工程师在2015年9月发布了包含通用无损数据压缩的Brotli增强版本,特别侧重于HTTP压缩。其中的编码器被部分改写以提高压缩比,编码器和解码器都提高了速度,流式API已被改进,增加更多压缩质量级别。新版本还展现了跨平台的性能改进,以及减少解码所需的内存。
与常见的通用压缩算法不同,Brotli使用一个预定义的120千字节字典。该字典包含超过13000个常用单词、短语和其他子字符串,这些来自一个文本和HTML文档的大型语料库。预定义的算法可以提升较小文件的压缩密度。
使用brotli取代deflate来对文本文件压缩通常可以增加20%的压缩密度,而压缩与解压缩速度则大致不变。
支持Brotli压缩算法的浏览器使用的内容编码类型为br,例如以下是Chrome浏览器请求头里Accept-Encoding的值:Accept-Encoding: gzip, deflate, sdch, br
82个字节,文件变的更小了
string filePath = Combine(CurrentDirectory, "streams.brotli"); FileStream fs = File.Create(filePath); using (Stream compressor = new BrotliStream(fs, CompressionMode.Compress)) { using (XmlWriter xml = XmlWriter.Create(compressor)) { xml.WriteStartDocument(); xml.WriteStartElement("infos"); xml.WriteElementString("info", "AY"); xml.WriteElementString("info", "2021"); xml.WriteElementString("info", "合肥"); xml.WriteEndDocument(); } } //输出压缩的文件 WriteLine("{0} 包含 {1:N0} 字节", filePath, new FileInfo(filePath).Length); WriteLine("压缩的内容"); WriteLine(File.ReadAllText(filePath)); WriteLine("读取压缩的内容"); fs = File.Open(filePath, FileMode.Open); using (Stream decom = new BrotliStream(fs, CompressionMode.Decompress)) { using (XmlReader xr = XmlReader.Create(decom)) { while (xr.Read()) { if ((xr.NodeType == XmlNodeType.Element) && xr.Name == "info") { xr.Read(); WriteLine(xr.Value); } } } }
NC2.1 引入管道 ,感兴趣看这篇:查看
C#8.0 和 NC3.0 引入了流的异步处理,后面第13篇博客会讲
ASCII
UTF-8
UTF-7
UTF-16
UTF-32
ANSI/ISO编码
string msg = "Hello AY"; byte[] en1=System.Text.Encoding.UTF8.GetBytes(msg); Console.WriteLine("HelloAY的编码后的长度,"+en1.Length); Console.WriteLine("Byte HEX CHAR"); foreach (var en in en1) { Console.WriteLine($"{en,4} {en.ToString("X"),4} {(char)en,5}"); } string decodeEn1 = System.Text.Encoding.UTF8.GetString(en1); Console.WriteLine(decodeEn1);
不同的编码,占用的字节数不一样
var reader = new StreamReader(stream, System.Text.Encoding.UTF8);
var writer = new StreamWriter(stream, System.Text.Encoding.UTF8);
常见的有两种,XML和JS对象的Json
NC有多个类,可以序列化为XML和JSON,也可以反序列化。
using System; using static System.IO.Path; using static System.Environment; using System.IO; using System.Collections.Generic; using System.Xml.Serialization;
var p = new List<Person>(); p.Add(new Person { Name = "杨洋1", Born = new DateTime(1991, 4, 4), Salary = 1000 }); p.Add(new Person { Name = "杨洋2", Born = new DateTime(1992, 5, 21), Salary = 2000 }); p.Add(new Person { Name = "杨洋3", Born = new DateTime(1991, 3, 23), Salary = 6000m, Children = new HashSet<Person> { new Person { Name = "ay1", Born = new DateTime(1992, 1, 4), Salary = 11000 }, new Person { Name = "ay1", Born = new DateTime(1999, 5, 6), Salary = 500M } } }); var xs = new XmlSerializer(typeof(List<Person>)); string path = Combine(CurrentDirectory, "people.xml"); using (FileStream stream = File.Create(path)) { xs.Serialize(stream, p); } //反序列化 using (FileStream xmlLoad=File.Open(path,FileMode.Open)) { var _1=(List<Person>) xs.Deserialize(xmlLoad); foreach (var item in _1) { Console.WriteLine($"{item.Name} {item.Born} {item.Salary}"); if (item.Children.Count > 0) { foreach (var subitem in item.Children) { Console.WriteLine($"\t\t{subitem.Name} {subitem.Born} {subitem.Salary}"); } } } }
可以使用xml的一些特性,使XML更紧凑
修改对象
public class Person { [XmlAttribute("sa")] public decimal Salary { get; set; } [XmlAttribute("na")] public string Name { get; set; } public HashSet<Person> Children { get; set; } [XmlAttribute("bo")] public DateTime Born { get; set; } }
这样名字更短了,文件更短
双击程序集名字
可以编辑csproj,在vs2019中 提示都有了
在vs2019中,也可以nuget方式
搜索newtonsoft.json,然后 你安装就行了
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net5.0</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> </ItemGroup> </Project>
var p = new List<Person>(); p.Add(new Person { Name = "杨洋1", Born = new DateTime(1991, 4, 4), Salary = 1000 }); p.Add(new Person { Name = "杨洋2", Born = new DateTime(1992, 5, 21), Salary = 2000 }); p.Add(new Person { Name = "杨洋3", Born = new DateTime(1991, 3, 23), Salary = 6000m, Children = new HashSet<Person> { new Person { Name = "ay1", Born = new DateTime(1992, 1, 4), Salary = 11000 }, new Person { Name = "ay1", Born = new DateTime(1999, 5, 6), Salary = 500M } } }); string jsonPath = Combine(CurrentDirectory, "person.json"); using (StreamWriter sw=File.CreateText(jsonPath)) { var jss = new Newtonsoft.Json.JsonSerializer(); jss.Serialize(sw,p); } Console.WriteLine(File.ReadAllText(jsonPath));
NC3.0引入 SYstem.Text.Json类,优化性能。
Json.NET是通过读取UTF-16来实现的。使用UTF-8读取JSON文档能带来更好的性能。
因为包括Http在内的大多数网络协议都使用UTF-8,而且可以避免在UTF-8与Json.NET的Unicode字符串值之间来回转换。
https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-apis/
引入
using System.Threading.Tasks;
using NuJson = System.Text.Json.JsonSerializer;
顶部
static void Main(string[] args)
修改为
static async Task Main(string[] args)
现在解析
var p = new List<Person>(); p.Add(new Person { Name = "杨洋1", Born = new DateTime(1991, 4, 4), Salary = 1000 }); p.Add(new Person { Name = "杨洋2", Born = new DateTime(1992, 5, 21), Salary = 2000 }); p.Add(new Person { Name = "杨洋3", Born = new DateTime(1991, 3, 23), Salary = 6000m, Children = new HashSet<Person> { new Person { Name = "ay1", Born = new DateTime(1992, 1, 4), Salary = 11000 }, new Person { Name = "ay1", Born = new DateTime(1999, 5, 6), Salary = 500M } } }); string jsonPath = Combine(CurrentDirectory, "person.json"); using (StreamWriter sw = File.CreateText(jsonPath)) { var jss = new Newtonsoft.Json.JsonSerializer(); jss.Serialize(sw, p); } var _text = File.ReadAllText(jsonPath); Console.WriteLine(_text); Console.WriteLine(); Console.WriteLine("开始解析"); using (FileStream jsonLoad=File.Open(jsonPath,FileMode.Open)) { var loadPeople = (List<Person>)await NuJson.DeserializeAsync(jsonLoad, typeof(List<Person>)); foreach (var item in loadPeople) { Console.WriteLine($"{item.Name} {item.Born} {item.Salary}"); if (item.Children!=null && item.Children.Count > 0) { foreach (var subitem in item.Children) { Console.WriteLine($"\t\t{subitem.Name} {subitem.Born} {subitem.Salary}"); } } } }
www.ayjs.net
抖音:wpfui 工作wpf,目前主maui
招聘合肥一枚WPF工程师,跟我一个开发组,10-15K,欢迎打扰
目前在合肥市企迈科技就职
AYUI8全源码 Github地址:前往获取
杨洋(AaronYang简称AY,安徽六安人)和AY交流
高中学历,2010年开始web开发,2015年1月17日开始学习WPF
声明:AYUI7个人与商用免费,源码可购买。部分DEMO不免费
不是从我处购买的ayui7源码,我不提供任何技术服务,如果你举报从哪里买的,我可以帮你转正为我的客户,并送demo
查看捐赠AYUI7.X MVC教程 更新如下:
第一课 第二课 程序加密教程
额 本文暂时没人评论 来添加一个吧
发表评论