7

正如我目前初步理解的那样:

DataInputStream是一个InputStream子类,因此它读取和写入字节。如果您正在读取字节并且您知道它们都将是ints 或其他一些原始数据类型,那么您可以使用 将这些bytes 直接读入原始数据类型DataInputStream

  • 问题:在读取内容之前,您是否需要知道正在读取的内容的类型(int、string 等)?整个文件是否需要由一种原始类型组成?

我遇到的问题是:为什么不使用InputStreamReader环绕InputStream的字节数据?使用这种方法,您仍在读取字节,然后将它们转换为表示字符的整数。哪些整数代表哪些字符取决于指定的字符集,例如“UTF-8”。

  • 问题:在什么情况下InputStreamReader,a 可以工作的地方不能DataInputStream工作?

我的猜测答案:如果速度真的很重要,并且您可以做到,那么将InputStream's 字节数据直接转换为原始 viaDataInputStream将是要走的路吗?这避免了Reader必须将字节数据“转换”为int第一个;并且它不依赖于提供字符集来解释返回的整数表示哪个字符。我想这就是人们所说的DataInputStream允许机器独立读取基础数据的意思。

  • 简化:DataInputStream可以将字节直接转换为原语。

激发整个事情的问题:我正在阅读以下教程代码:

    FileInputStream fis = openFileInput("myFileText");

    BufferedReader reader = new BufferedReader( new InputStreamReader( new DataInputStream(fis)));

    EditText editText = (EditText)findViewById(R.id.edit_text);

    String line;

    while(  (line = reader.readline()) != null){

        editText.append(line);
        editText.append("\n");
    }

...我不明白为什么讲师选择使用new DataInputStream(fis)它,因为它看起来没有任何直接从字节转换为原语的能力被利用?

  • 我错过了什么吗?

感谢您的见解。

4

6 回答 6

11

InputStreamReader 和 DataInputStream 完全不同。

DataInputStream 是 InputStream 的子类,因此它读取和写入字节。

这是不正确的,InputStream 只读取字节,而 DataInputStream 扩展它,因此您也可以读取 Java 原语。他们都无法写入任何数据。

问题:在读取内容之前,您是否需要知道正在读取的内容的类型(int、string 等)?整个文件是否需要由一种原始类型组成?

DataInputStream 只能用于读取先前由 DataOutputStream 写入的数据。如果不是这种情况,则您的 DataInputStream 不太可能“理解”您正在读取的数据并将返回随机数据。因此,您应该确切地知道相应的 DataOutputStream 以何种顺序写入了哪种类型的数据。

例如,如果您想保存应用程序的状态(假设它由几个数字组成):

public void exit() {
    //...
    DataOutputStream dout = new DataOutputStream(new FileOutputStream(STATE_FILE));
    dout.write(somefloat);
    dout.write(someInt);
    dout.write(someDouble);
}

public void startup() {
    DataInputStream dout = new DataInputStream(new FileInputStream(STATE_FILE));
    //exactly the same order, otherwise it's going to return weird data
    dout.read(somefloat);
    dout.read(someInt);
    dout.read(someDouble);
}

这基本上就是 DataInputStream 和 DataOutputStream 的全部内容:将原始变量写入流并读取它们。

现在,InputStreamReader 完全不同了。InputStreamReader 将编码文本“翻译”为 Java 字符。您基本上可以使用任何文本流(知道其编码)并使用 InputStreamReader 从该源读取 Java 字符。

使用这种方法,您仍在读取字节,然后将它们转换为表示字符的整数。哪些整数代表哪些字符取决于指定的字符集,例如“UTF-8”。

字符编码不仅仅是代码点和字符之间的简单映射。除此之外,它还指定了代码点在内存中的表示方式。例如,UTF-8 和 UTF-16 共享相同的字符映射,但如果您尝试将 UTF-8 流读取为 UTF-16,则 InputStreamReader 会严重失败。由四个字节 un UTF-8 ('a', 'a', 'b', 'b') 表示的字符串 aabb 将被转换为两个字符。两个 a 和 b 的值将被视为一个字符。我懒得去查那些会是哪些角色,但他们会很奇怪。

InputStreamReader 处理所有这些内容,因此如果您知道编码,则能够从任何源读取文本(与 DataInputStream 不同)。

问题:在什么情况下 InputStreamReader 无法在 DataInputStream 可以工作的地方工作?

这一点现在应该很清楚了。由于这两个类的目的完全不同,所以你不应该问这个问题。InputStreamReader 不会DataInputStream 那样将字节转换为整数,也不是为此目的而设计的。

在教程代码中,我很确定您可以省略 DataInputStream:

BufferedReader reader = new BufferedReader( new InputStreamReader(fis));

但是,DataInputStream 提供了与 InputStream 相同的方法,这就是为什么将 FileInputStream 包装在其中并没有错(尽管没有必要)。

于 2014-08-26T17:54:51.703 回答
2

你教授的例子非常具有误导性。

从 API 中,它说DataInputStream:“以与机器无关的方式从底层输入流中读取原始 Java 数据类型”。回到 Java v 1.0,这一点更为重要,因为 HTML、XML 和 JSON 等通信协议不存在或处于起步阶段。int所以最大的问题是s,longs, s等的大端/小端问题float。使用原始套接字从大端计算机到Java中的小端计算机通信需要这样的东西。

但这与阅读文本文件无关。我建议使用FileReader连接到BufferedReader,而不是您的教授所做的。

于 2014-08-26T17:36:34.140 回答
0

DataInputStream具有读取二进制数据的其他方法,例如将四个字节读取为 32 位整数。它仍然是一个InputStream.

AInputStreamReader接受一个InputStream字节流,并将它们转换为具有编码的字符流(Reader)。它可以用于文本文件。

将两者结合起来没有任何效果,因为DataInputStream不会改变InputStream.

于 2014-08-26T17:55:23.997 回答
0

InputStreamReader如果要读取基于字符的流,则使用。例如来自标准输入或属性文件。DataInputStream是如果您想以与机器无关的方式读取原始流,例如从套接字读取。如果您希望速度和存储大小超过可读性,则应该使用DataInputStreamover 。InputStreamReader以二进制形式存储数据通常比以人类可读格式存储要快得多,占用的空间也更少。InputStreamReader如果您正在解析人类可读的格式,例如 XML 或 HTTP,则应该使用。

于 2014-08-26T17:37:33.590 回答
0

DataInputStream用于从二进制文件中读取简单数据,例如整数、字符串、对象等。(与 ASN.1、音频或图像之类的东西相反,尽管它们可以在 a 之上实现DataInputStream,但这是题外话。) InputStreamReader用于从字节流转换为字符流。

就示例代码而言,这是:

FileInputStream fis = ...;
BufferedReader reader = new BufferedReader(
    new InputStreamReader( 
        new DataInputStream(fis)
    )
);

和这个:

FileInputStream fis = ...;
BufferedReader reader = new BufferedReader(
    new InputStreamReader(fis)
);

做完全相同的事情,除了第一个效率稍低。

于 2014-08-26T17:38:36.073 回答
0

在阅读了这些精彩的回复后,我想吸收这些知识并巩固它。这是一个演示如何DataInputStreamDataOutputStream工作的小程序。对我来说最大的收获之一是:使用这些流,您必须知道正在读取的数据的类型顺序。所以这是一段完整的代码,它使用 DataOutputStream 将对象实例字段保存到文件中,然后从文件中读取这些字段,重新制作对象,然后打印。

package StackoverflowQuestion25511536;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
* Earthlings writes a collection of Earthling Peeps to
* a file using DataInputStream, then reads the collection. 
* 
* The intent of this class is to demonstrate that
* DataInputStream & DataOutputStream require knowledge
* of the data (types and order) that is written to a file so 
* that it can be meaningfully interpreted when read.
* 
* Using object serialization and ObjectInputStream
* and ObjectOutputStream should be considered.
* 
* Detection of end of file (EOF)
* is determined using technique taught in "Introduction to Java 
* Programming", 9th ed, by Y. Danial Liang.  
* 
* @author Ross Studtman
*/
public class Earthlings {   

List<Peeps> peepCollection = new ArrayList<Peeps>();

public static void main(String[] args){
    new Earthlings().run(); 
}

public void run(){
    makePeeps();
    writeAndRead();
}

public void makePeeps(){    
    peepCollection.add(new Peeps("Ross", 45, 6.9));
    peepCollection.add(new Peeps("Lebowski", 42, 7.8));
    peepCollection.add(new Peeps("Whedon", 50, 8.8));       
}

// When end of file reached an EOFException is thrown.
public void writeAndRead(){

    DataOutputStream output = null;
    DataInputStream input = null;

    try{
        // Create DataOutputStream
        output = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("peeps.oddPeople")));

        // Iterate over collection
        for(Peeps peep : peepCollection){

            // Assign instance fields to output types.
            output.writeUTF(peep.getName());
            output.writeInt(peep.getAge());
            output.writeDouble(peep.getOddness());
        }

        // flush buffer to ensure everything is written.
        output.flush();

        // Close output
        output.close();

        // Create DataInputStream
        File theSavedFile = new File("peeps.oddPeople");            
        input = new DataInputStream(new BufferedInputStream(new FileInputStream(theSavedFile)));

        // How many bytes are in this file? Used in for-loop as upper iteration limit.
        long bytes = theSavedFile.length();

        // Reconstitute objects & print             
        for(long counter = 0 ; counter < bytes; counter++ ){  // EOFException thrown before 'counter' ever equals 'bytes'.

            String name = input.readUTF();
            int age = input.readInt();
            double oddity = input.readDouble();

            // Create and print new Peep object.
            System.out.println(new Peeps(name, age, oddity));
        }


    }catch(EOFException e){
        System.out.println("All data read from file.");         
    }catch(IOException e){
        e.printStackTrace();
    }finally{
        if(input != null){
            try {
                input.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }           
    }
}   

/**
 * Simple class to demonstrate with.
 */
class Peeps{        
    // Simple Peep info
    private String name;
    private int age;
    private double oddness;

    // Constructor
    public Peeps(String name, int age, double oddness) {
        super();
        this.name = name;
        this.age = age;
        this.oddness = oddness;
    }

    // Getters
    public String getName() { return name;}
    public int getAge() { return age;}
    public double getOddness() { return oddness;}

    @Override
    public String toString() {
        return "Peeps [name=" + name + ", age=" + age + ", oddness=" + oddness + "]";
    }           
}

}

于 2014-08-27T17:05:08.853 回答