DataInputStream vs InputStreamReader,试图在概念上理解这两者

时间:2014-08-26 17:14:08

标签: java datainputstream inputstreamreader

我暂时理解它:

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

  • 问题:在阅读之前,您是否需要知道正在阅读的内容的类型(int,string等)?并且整个文件是否需要包含一个原始类型?

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

  • 问题: InputStreamReaderDataInputStream可行的情况下InputStream无效?

我的猜测答案:如果速度非常重要,你可以做到,那么将DataInputStream的字节数据直接转换为原始文件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)

...我不明白教师为什么选择使用{{1}},因为看起来没有任何能够直接从字节转换为基元的能力?

  • 我错过了什么吗?

感谢您的见解。

6 个答案:

答案 0 :(得分:6)

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将显着失败。 字符串aabb,由四个字节UTF-8表示(' a'' a'' b'' b')将被转换为两个字符。两个a和b的值将被视为一个字符。我懒得查看那些人物,但他们会非常奇怪。

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

  

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

现在应该很清楚了。由于两个课程的目的完全不同,因此您不应该提出这个问题。 InputStreamReader 将字节转换为整数,如DataInputStream,并不是为此目的而设计的。

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

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

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

答案 1 :(得分:1)

你的教授的例子非常误导。

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

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

答案 2 :(得分:0)

如果要读取基于字符的流,则使用

InputStreamReader。例如来自标准输入或属性文件。 DataInputStream是指您希望以独立于计算机的方式读取原始流,例如来自套接字的原始流。如果您希望速度和存储空间大小超过可读性,则应使用DataInputStream而不是InputStreamReader。以二进制形式存储数据通常比以人类可读格式存储数据更快且占用更少的空间。如果要解析人类可读的格式(例如XML或HTTP),则应使用InputStreamReader

答案 3 :(得分:0)

DataInputStream用于从二进制文件中读取简单数据,例如整数,字符串,对象等(与ASN.1,音频或图像相反,虽然它们可以在DataInputStream之上实现,但那是关于主题的。){{ 1}}用于从字节流转换为字符流。

就示例代码而言,这是:

InputStreamReader

和此:

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

做同样的事情,除了第一个效率稍差。

答案 4 :(得分:0)

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

InputStreamReader获取InputStream这是一个字节流,并将它们转换为带编码的字符流(Reader)。它可以用于文本文件。

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

答案 5 :(得分:0)

在阅读了这些精彩的回答之后,我想要掌握这些知识并巩固它。这是一个迷你程序,展示了DataInputStream& DataOutputStream工作。对我来说最大的收获之一是:通过这些流,您必须知道正在读取的数据的类型顺序。因此,这是一段完整的代码,它使用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 + "]";
    }           
}

}