将字符串写入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原创文章,未经博主允许不得转载。

Java读取文件内容到byte[]数组中

有时候,我们需要将读取文件的内容到一个byte[] 数组中,然后对这个数组进行一些修改,这时,我们可以借助于 ByteArrayOutputStream 这个类来实现。ByteArrayOutputS...

java byte数组与文件读写

将一个文件内的所有内容读取到byte数组,也可以把一个byte[]的内容写入到文件中。可以作为复制文件的方法 import java.io.ByteArrayOutputStream; impo...

读取文件到byte[]数组,将byte[]写入到指定文件中

public static void main(String[] args) { File file = new File("D:\\GBJ_TOOLS\\download\\apac...

将byte数组写入文件

public static void writeBytesToFile() throws IOException{ String s = "aaaaaaaa"; byt...
  • xifei66
  • xifei66
  • 2017年01月12日 10:16
  • 1884

定义一个文件输入流,调用 read(byte[] b)方法将 exercise.txt 文件中的所有内容打印出来 (byte 数组的大小限制为 5)。

package com.heima.test;import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import ...

GlassFish 的安装及设置命令

GlassFish 命令行操作   本文链接   GlassFish 是一款强悍的 J2EE 应用服务器,支持完整的 J2EE 标准,而且开源免费,如果服务器配置不是特别低,若2G以上内存我强烈推荐G...
  • joyous
  • joyous
  • 2012年09月23日 01:27
  • 26515

android JIN 第一步 生成java转换成class然后再转化成.h文件

经过一番查找,可算搞定了java转成c的.h头文件的这第一步。 方法如下 第一步:创建 native方法的java类。 方法 m1和m2分别是调用native。 package com.demo.s...

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

package cn.edu.jit.test; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; impo...
  • qian_ch
  • qian_ch
  • 2017年02月19日 15:55
  • 648

读取文本字符串,并生成以字符串命名的txt文件

从test.txt文本中逐行读取字符串,以字符串命名,生成新的txt文档 #-*- coding:UTF-8 -*- #读取字符串,去除字符串中的“\n”,并生成txt文件 if __name__==...
  • cqylqq
  • cqylqq
  • 2016年05月05日 15:55
  • 147

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

1、 自定义泛型 l        泛型的目的也是为了代码重用(算法重用) classMyListGeneric {         T[] arr = new T[100];     ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:将字符串写入txt,然后得到这个文件的byte[],生成文件这个过程真的有必要吗?
举报原因:
原因补充:

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