将字符串写入txt,然后得到这个文件的byte[],生成文件这个过程真的有必要吗?

故事起源于一个简单的上传功能,功能要求是这样的,将数据按照指定格式拼接,然后写入txt文件,再通过请求对方api进行文件上传。

故事背景有了,然后下面介绍故事走向。

按个人以往的尿性,肯定是直接将内容按指定编码写入txt中,然后上传了事,但故事(或者说事故)之所以是故事,就在于它一定是不按惯例走的,所以这次理所当然的,脑子必须抽了,然后想到这个txt文件生成是必须的吗?文件内容我都有了,我为什么还要通过IO写入文件,然后再读取上传呢?我是不是可以直接确认字符串写入txt文件后与原始字符串有什么区别,通过修正区别来得到要上传的文件byte数组呢?

想到了当然要动手尝试下,于是下面的测试代码就产生了

        static void FileConvertDemo(Encoding encoding)
        {
            string filePath = @"E:\test.txt";
            string content = "测试内容";
            var color = Console.ForegroundColor;
            var titleColor = ConsoleColor.Magenta;
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine("******************    " + encoding.BodyName + "    ******************");
            Console.ForegroundColor = color;
            byte[] datas;

            Console.ForegroundColor = titleColor;
            Console.WriteLine("测试直接Encoding获取byte[]的代码");
            Console.ForegroundColor = color;
            datas = encoding.GetBytes(content);
            Console.WriteLine("数组长度:" + datas.Length);
            Console.WriteLine(BitConverter.ToString(datas));

            Console.ForegroundColor = titleColor;
            Console.WriteLine("测试将内容通过原生方法指定Encoding后写入文件的方式获取byte[]的代码");
            Console.ForegroundColor = color;
            File.WriteAllText(filePath, content, encoding);
            datas = File.ReadAllBytes(filePath);
            Console.WriteLine("数组长度:" + datas.Length);
            Console.WriteLine(BitConverter.ToString(datas));
        }
然后测试要全面,所以这里将所有默认的字符编码都测试一下
            List<Encoding> list = new List<Encoding>()
            {
                Encoding.ASCII,
                Encoding.BigEndianUnicode,
                Encoding.UTF8,
                Encoding.UTF7,
                Encoding.UTF32,
                Encoding.Unicode,
                Encoding.GetEncoding("gb2312"),
                Encoding.GetEncoding("gbk"),
            };
            list.ForEach(encoding => FileConvertDemo(encoding));
测试结果,呵呵哒,很顺利的就发现规律明显,根据编码不同,文件加上了不同的标头,如下图,除了差异部分(草绿色方框和淡蓝色方框),其它位置的byte都是一样的

所以我现在只要测试补充上差异标头后,得到的byte[]是不是就是写入文件后的byte[],所以下面这段代码产生了

    using System.Collections.Concurrent;
    using System.IO;
    public interface IFileConverter
    {
        /// <summary>
        /// 获取指定内容输出到指定文本后,File.ReadAllBytes应当读取到的byte数组
        /// </summary>
        /// <param name="contents">要写入文件的内容</param>
        /// <param name="filePath">文件要保存的物理位置</param>
        /// <returns></returns>
        byte[] GetFileBytes(string contents, string filePath);
    }
    public class TxtFileConverter : IFileConverter
    {
        public TxtFileConverter()
        {
            this.Encoding = Encoding.UTF8;
        }
        public Encoding Encoding { get; set; }
        public byte[] GetFileBytes(string contents, string filePath = null)
        {
            //File.WriteAllText(filePath, contents, this.Encoding);
            byte[] stringBytes = this.Encoding.GetBytes(contents);
            byte[] result = stringBytes;
            var flags = EncodingFlagHelper.GetEncodingFlags(this.Encoding);
            if (flags.Length > 0)
            {//不生成物理文件,直接通过文件头来补充缺少的字节
                result = new byte[flags.Length + stringBytes.LongLength];
                Array.Copy(flags, result, flags.Length);
                Array.Copy(stringBytes, 0, result, flags.Length, stringBytes.LongLength);
            }
            return result;
        }

        class EncodingFlagHelper
        {
            static readonly ConcurrentDictionary<string, byte[]> Dictionary = new ConcurrentDictionary<string, byte[]>();
            /// <summary>
            /// 根据当前编码类型获取对应txt的编码标识
            /// </summary>
            /// <param name="encoding"></param>
            /// <returns></returns>
            public static byte[] GetEncodingFlags(Encoding encoding)
            {
                return Dictionary.GetOrAdd(encoding.BodyName, name =>
                {
                    //因为空字符串输出数组就是个零长数组,所以可以简单的通过写一个空字符串到文本中来得到编码标识
                    string content = string.Empty;
                    string tmpFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "~tmpFlags");//可能存在权限问题,所以不用Path.GetTempFileName()
                    File.WriteAllText(tmpFile, content, encoding);
                    var flags = File.ReadAllBytes(tmpFile);
                    File.Delete(tmpFile);
                    return flags;
                });
            }
        }
    }
下面就是加上这部分的测试代码,在FileConvertDemo方法内追加下列代码
            Console.ForegroundColor = titleColor;
            Console.WriteLine("测试不生成文件,通过补位的方式获取byte[]的代码");
            Console.ForegroundColor = color;
            datas = new TxtFileConverter() { Encoding = encoding }.GetFileBytes(content, filePath);
            Console.WriteLine("数组长度:" + datas.Length);
            Console.WriteLine(BitConverter.ToString(datas));
然后运行,输出结果如下图

最后上传测试这里就不做了,因为实际项目中比目前还要复杂,文件生成后还有加解密、解压缩,其中加解密要求的原始内容就是byte[],这里可以不需做任何处理,解压缩部分需要Stream,byte作为参数传给MemoryStream即可,当然你真想验证结果,那么可以试下File.WriteAllBytes来比较是否与File.WriteAllText一致。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值