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

原创 2016年07月20日 19:55:46

故事起源于一个简单的上传功能,功能要求是这样的,将数据按照指定格式拼接,然后写入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一致。

版权声明:本文为starfd原创文章,未经博主允许不得转载。

相关文章推荐

Unity 数据库的简单使用

1.创建一个Unity工程,创建一个文件夹命名为Plugins 2.导入两个文件到Plugins文件夹(Mono.Data.Sqlite.dll和System.Data.dll) 3.新建一个脚本...

Unity 简单的文件写入与读取

我们在进行文件的写入和读取时必须要确定一个路径,那我们就需要用到获取路径的方法 Unity中获取路径的方法是:Application.dataPath; 然而还有获取一个临时的路径:Applica...

VC++向txt文件中写入字符串

VC++向文件中输入数据的时候得到一堆数据,在txt文件中看到的是乱码。

将字符串写入txt中

import java.io.BufferedWriter;   import java.io.File;   import java.io.FileWriter;   import java.io....

定义一个文件输入流,使用read(byte[] b)方法,将a.txt文件中的内容打印出来

package cn.edu.jit.test; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; impo...

黑马程序员_学习日记40_605基础加强(自定义泛型、装拆箱、foreach、文件操作、字符串与byte数组转换)

1、 自定义泛型 l        泛型的目的也是为了代码重用(算法重用) classMyListGeneric {         T[...

关于vs2010 中c++输出字符串到txt文件中的格式问题

背景说明 最近在研究输出一种文件格式,其实是输出字符串到txt文件,但是该文件格式比较成熟,对各个输出的记录都有确定的格式要求,这些格式让我看的很是头疼,比如Format(80A1),Format(...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)