了解java中的Binary,ByteStream和Characters

时间:2014-01-02 03:15:43

标签: java stream binary char java-io

我在消化Java IO类中的一些概念时遇到了一些困难。例如,有两种类型的流,byte和char。据我所知,字节流逐字节读取。

1。如果java中的char存储为16位(双字节)数据类型,那么我怎样才能使用面向字节的输入流从文件中准确读取char(比如'A'),例如。的FileInputStream?

2。是否我使用的字符(主要在ascii图表中的0到122之间)存储在分配的两个字节的一个字节中?

3。 DataInputStream / DataOutputStream允许我读写二进制数据,像FileInputStream / FileOutputStream这样的其他输入流允许我读写什么到底是什么?我基本上想知道当我希望输出数据作为我可以阅读的文本(使用像记事本这样的简单文本编辑器)而不是我希望它编码为原始二进制数据(文本看起来像记事本中的垃圾)时使用哪个流?

努力理解java中的流的概念以及何时使用。

3 个答案:

答案 0 :(得分:3)

取决于您正在阅读的文件的格式。

如果文件是ASCII字节流,则执行以下操作:

InputStream is = new FileInputStream( filePath );
Reader reader = new InputStreamReader( is, "ISO-8859-1" );

char ch = reader.read();

您始终首先在面向字节的文件上打开输入流。然后,InputStreamReader将字节转换为字符。当然,在这种情况下,ISO-8859-1是从单字节值到完全相同的字符值的映射。显然,其他映射也是可能的,但ISO-8859-1恰好与Unicode集的前255个字符相同,其中前127个恰好与ASCII相同。

写作时使用:

OutputStream os = new FileOutputStream( filePath ) ;
Writer w = new OutputStreamWriter( os, "ISO-8859-1" );

w.write( ch );

再一次,是OutputStreamWriter根据ISO-8859-1字符集适当地在字符和字节流之间进行转换。生成的文件每个字符有一个字节。

以下是proper basic stream patterns的一些示例。

如果使用上述内容,请执行以下命令:

w.write("AAAA");
w.flush();
w.close();

生成的文件将包含4个字节,每个字节的值为65。使用顶部的代码读取该文件将在内存中产生四个“A”字符,但在内存中,每个字符占用16位。

如果文件是用不同的字符集编码的,可能包括多个字节字符,那么只需在InputStreamReader / OutputStreamWriter中使用正确的编码,就可以在读写时进行正确的转换。

UTF-8不是字符集,而是将常规unicode字符编码为字节序列,结果证明UTF-8编码非常聪明,因为unicode字符的前127个字符被映射到前127个字节值(单个字节本身)。然后字符> = 128在一行中使用2个或更多字节值,其中每个字节值都是> = 128.如果你知道ascii文件只使用“7位”ASCII,那么UTF-8也适合你。对于Java,通常UTF-8是用于文件的最佳编码,因为它可以正确编码所有可能的Java char值而不会丢失。

了解有关溪流的知识非常重要。我建议您不要尝试以任何其他方式将字节转换为字符。当然,这是可能的,但是由于流中的转换非常可靠和正确,所以这是浪费精力。

(它变得更糟......实际上一个字符是32位数量,其中20位可以编码为16位字符值的序列,编码称为UTF-16。建议您暂时忽略它,但请注意,即使在由16位字符值组成的Java字符串中,也存在一些双字符序列。)

答案 1 :(得分:1)

  

如果java中的char存储为16位(双字节)数据类型,它是怎么回事   我可以准确地从一个文件中读取一个字符,比如'A'   面向字节的输入流,例如。的FileInputStream?

尝试

System.out.println(Integer.toBinaryString('A'));

打印出字符'A'的二进制表示。这打印

1000001

由于'A'char,因此实际上存储了16位

00000000 01000001

所以你要做的就是读取两个连续的字节并适当地使用它们来形成char。看到实际行动

ByteBuffer buffer = ByteBuffer.wrap(new byte[] {0b00000000, 0b01000001});
System.out.println(buffer.getChar());

打印

A

这样做是采用数组中的第一个byte并将其用作char中的前8位,将第二个byte用作后8位。


  

DataInputStream / DataOutputStream允许我读写二进制文件   数据,其他输入流如FileInputStream / FileOutputStream允许   我要读写什么呢?我基本上想知道哪个   当我希望输出数据作为我可以读取的文本时使用流(使用   简单的文本编辑器,如记事本),而不是我希望它编码为原始   二进制数据(在记事本中看起来像垃圾的文本)?

无论是编写文本还是其他任何内容,都是位和字节。你可以做得很好

"someString".getBytes()

并写下那些。所以这并不重要。使用最能代表你正在做的事情。通常情况下,您可以使用OutputStream包含基础PrintWriter,使用InputStreamScanner包含基础BufferedReader

答案 2 :(得分:1)

在我尝试回答你的问题之前,很少有基本的东西需要理解。

  1. 在最低级别InputStream/OutputStream),所有内容都是位和字节。因此,最低级别的流处理原始数据,即位/字节。
  2. 现在要将原始字节转换为可读字符,您需要字符编码或Character Set。简而言之,字符编码是一条指令(从字节到可视字符的映射),用于将原始字节转换为定义集合中的可读字符(例如UTF-8)。
  3. 现在回答你的问题:

    如果java中的char存储为16位(双字节)数据类型,那么我怎样才能使用面向字节的输入流从文件中准确读取char,例如'A',例如。的FileInputStream?

    为了读取字符数据,原始输入流包含在面向字符的流中,例如

    FileInputStream fis = new FileInputStream("test.txt");
    InputStreamReader isr = new InputStreamReader(fis, "UTF8"); 
    

    正如javadoc所说InputStreamReader 是从字节流到字符流的桥梁

    我使用的字符(主要在ascii图表中的0到122之间)是否存储在分配的两个字节的一个字节中?

    是。 ascii charset是较大的Unicode集的子集,如UTF-8

    DataInputStream / DataOutputStream允许我读取和写入二进制数据,其他输入流如FileInputStream / FileOutputStream允许我读写什么?

    我想现在显而易见的是,DataInputStream/DataOutputStream用于字符数据,而ileInputStream/FileOutputStream用于原始数据。

    我基本上想知道当我希望输出数据作为我可以读取的文本(使用像记事本这样的简单文本编辑器)而不是我希望它编码为原始二进制数据(文本看起来像记事本中的垃圾)?

    对于文本使用任何读者/作者(Here is an example