Java IO流

2018-04-20  本文已影响10人  sunboximeng

I/O 是人与机器或者机器与机器交互的手段,Java中将输入输出抽象称为流,就好像水管将两个容器连接起来。IO的核心问题是将什么样的数据(字节、字符)写到什么地方(文件(磁盘)、控制台、内存中的缓存、网络(socket)、管道(线程内部通信)。操作系统实现了协议栈、对磁盘的抽象,于是应用程序可以直接使用socket和文件。

常用的上传和下载使用的就是IO流技术。上传超过大小限制就会引发异常,要加载的图片由于网络原因也不一定成功,所以IO流会涉及到文件类和异常类。

IO流的分类

如何区分输入与输出:以Java程序自身为参照物。

1. 字节流抽象类:InputStreamOutputStream.
2. 字符流抽象类:ReaderWriter.
3. 转换流(属于包装流):InputStreamReaderOutputStreamWriter

注意:1. 文件结束的判断:read()方法返回-1时。
2. read()方法就像迭代器里的next()方法一样,会记忆位置。因此读文件的代码就像是利用迭代器遍历集合的代码,需要利用while循环。

4. 高效流(属于包装流)

Most of the examples we've seen so far use unbuffered I/O. This means each read or write request is handled directly by the underlying OS. This can make a program much less efficient, since each such request often triggers disk access, network activity, or some other operation that is relatively expensive.
To reduce this kind of overhead, the Java platform implements buffered I/O streams. BufferedInputStreams read data from a memory area known as a buffer; the native input API is called only when the buffer is empty. Similarly, BufferedOutputStreams write data to a buffer, and the native output API is called only when the buffer is full.

5. 序列化流(属于包装流,可以包装文件流)
6. 打印流(属于缓冲流,高效)

IO流应用:文件复制(输入+输出)、图片加密(输入+异或+输出)、极简爬虫(输入+正则表达式+输出)。

7. Properties类

是Map的实现类,键值都是String类型(因此也就不用像HashMap那样写泛型了吧),是唯一可以与IO流结合使用的集合类,用于读写配置文件。
System类下面有一个静态方法:public static Properties getProperties(),其返回值就是Properties类型的。返回当前系统的属性,比如java版本、操作系统名称、文件分隔符、路径分隔符、行分隔符、文件默认编码。

例子: 文件复制

To demonstrate how byte streams work, we'll focus on the file I/O byte streams: FileInputStream and FileOutputStream.

FileInputStream in = null;
FileOutputStream out = null;
in = new FileInputStream("input.txt");
out = new FileOutputStream("output.txt");
while (in.read() != -1) {
  out.write(c);
}
in.close();
out.close();

它的available()方法返回文件的大小。可以据此设定字符数组的大小,然后将此字符数组传入read()方法。

IO异常处理代码
//写文件の4步全都会报错,因此都会放在try里面。
FileWriter fw = null; //放在try里面,finally就用不了了。
try {
    fw = new FileWriter("d.txt"); //这里一报错,不仅文件写不了,还会引发空指针。
    fw.write("hello");
    fw.flush();
} catch (IOException e) {
    e.printStackTrace();
} finally {
        // 文件路径可能会错,导致文件没有创建成功,导致fw并没有被赋值
    if (fw != null) {
        try {
            fw.close(); //确保在上面代码抛异常的情况下,也能关闭资源
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}   

JDK7之后,finally里面的代码全部可以省略,因为会自动关闭:

//有多个流对象的话就用分号隔开。
try (FileWriter fw = new FileWriter("d.txt")) {
    fw.write("hello");
    fw.flush();
} catch (IOException e) {
    e.printStackTrace();
} 

会自动关闭的原因:实现了AutoCloseable接口,它有一个close方法。只有实现了这个接口的对象才能放到try后面,最后会自动调用close方法。代码验证:

public class Student implements AutoCloseable {
    @Override
    public void close() throws Exception {
        System.out.println("亲,已为您自动关闭 Student 对象!");
    }
}

Scanner类

The scanner API breaks input into individual tokens, and translating individual tokens according to their data type.
By default, a scanner uses white space to separate tokens(White space characters include blanks, tabs, and line terminators),因此如果想读一整行,就需要用nextLine方法。 既然要parse,所以处理的肯定是字符流。字节流像图片视频没有处理的必要。
Scanner类也可以用来读文件,读取的单位(字节、字符、数字、对象)、高效方便的方法是由选取的流来决定的。
Scanner最方便的就是可以自动把数字字符串识别成数字。

Scanner s = null;
s = new Scanner(new BufferedReader(new FileReader("input.txt")));
// 和迭代器一样,迭代器里面就有hasNext方法和Next方法。
// 所以读取字符串就是写一个迭代器的过程。
while (s.hasNext()) {
  System.out.println(s.next());
}
s.close();

The above example treats all input tokens as simple String values. Scanner also supports tokens for all of the Java language's primitive types (except for char).

可以很方便的读数字:

Scanner s = null;
double sum = 0;
s = new Scanner(new BufferedReader(new FileReader("input.txt")));
//可以把想要的类型选择出来
while (s.hasNext()) {
  if (s.hasNextDouble()) {
      sum += s.nextDouble();
  } 
  else {
    s.next();
  }   
}
s.close();

从键盘读取:Scanner input = new Scanner(System.in)
input就有nextInt()nextLine()方法
从文件读取:Scanner input = new Scanner(file path)

从键盘读数据写到文件。

标准输入输出

Scanner类是在JDK1.5之后才有的,之前的标准输入输出用的是System类。

java.lang.System
public final class System extends Object{
  static PrintStream err; // 标准错误流
  static InputStream in; // 标准输入(从键盘输入)
  static PrintStream out; // 标准输出流(向显示器输出)
}

输出重定向:

// 此时直接输出到屏幕  
System.out.println( "hello" );  
File file = new File( "d:" + File.separator + "hello.txt" );  
try{  
System.setOut( new PrintStream( new FileOutputStream(file) ) );  
}catch( FileNotFoundException e ){  
    e.printStackTrace();  
}  
System.out.println( "这些内容在文件中才能看到哦!" );  

输入重定向:
System.setIn( newFileInputStream(file) );

Command-line

命令行的标准输入是命令行参数,标准输出是terminal window。
重定向命令行的标准输入输出:
java Average 4 < input.txt > out.txt

上一篇 下一篇

猜你喜欢

热点阅读