1. Java中的“流”
在大多数程序中,都需要对输入输出进行处理。例如我们在前面各个章节中需要获取用户从键盘上的输入,需要在控制台输出结果等等。除此之外还有从文件中读取数据,向文件中写入数据等等。在Java中,我们把这些不同类型的输入输出源抽象地称为流,也就是Stream;在里面输入输出的数据则称为数据流(Data Stream),它们通常具有统一的接口。
于是我们得到了数据流的定义:
一个Java I/O对象叫做数据流。读取数据到内存的对象叫做输入流,内存写出数据的对象叫做输出流。
可以大致将流分为下面几种类型:
- 按照数据流的方向不同分为输入流和输出流。这种分类不是绝对的,例如在向一个文件写入数据时,它就是输出流;而在读取数据时,它就是输入流。
- 按照处理数据的单位不同分为字节流和字符流。
- 按照功能的不同分为节点流和处理流。
需要特别说明,节点流是从特定的数据节点(文件、数据库、内存等)读写数据;处理流是连接在已有的流上,通过对数据的处理为程序提供更多功能。
在Java环境中,java.io包提供了大多数的类和接口来实现输入输出管理。一些标准的输入输出则来自java.lang包中的类,但它们都是继承自java.io中的类。我们可以将输入流理解为数据的提供者,而把输出流理解为数据的接收者。在最初的时候,这些派生自抽象类InputStream和OutputStream的输入输出类是面向8位的字节流的。但为了支持国际化,又引入了派生自抽象类Reader和Writer的类层次,用于读写一些双字节的Unicode字符。
因此,在学习java的输入输出上,我们希望你以字节流和字符流作为区分来学习。
字节流和字符流:
字节流:表示以字节为单位从stream中读取或往stream中写入信息。通常用来读取二进制数据。
字符流:以Unicode字符为单位从stream中读取或往stream中写入信息。
java中流的层次结构如下:
字节流与字符流的区别
实际上字节流在操作时本身不会用到缓冲区(内存),是文件本身直接操作的,而字符流在操作时使用了缓冲区,通过缓冲区再操作文件。
2. 读写一个文件
2.1 使用FileInputStream读取文件
首先在桌面上新建一个txt文件,命名为Test。在Test文件中输入内容a,然后保存并关闭。
字节流中读取文件的方式主要有两种方法:**
int read(),从此输入流中读取一个数据字节。返回:下一个数据字节。如果已到达文件末尾,则返回 -1。
int read(byte[] b),从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。返回:读入缓冲区的字节总数,如果因为已经到达文件末尾而没有更多的数据,则返回 -1。
创建包含main()方法的类ReadFileTest,代码如下:
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; public class ReadFileTest { public static void main(String[] args){ try{ FileInputStream file = new FileInputStream("C:/Users/Administrator/Desktop/Test.txt"); int data = 0; while((data = file.read())!=-1){ System.out.println(data); } file.close(); }catch(FileNotFoundException e){ e.printStackTrace(); }catch(IOException e){ e.printStackTrace(); } } }
97
上述代码运行结果为97,因为a的ASCLL码值刚好为97.
2.2 读取文件的其他方式
如果你想使用BufferedInputStream来读取文件,在创建对象时使用下面的格式即可:
BufferedInputStream file = new BufferedInputStream(new FileInputStream("文件的路径")); 同时import java.io.BufferedInputStream;。
上述方法都是对于字节流的,那么对于字符流呢?
查阅API文档可以知道,字节流使用的数组是字节数组byte[] bt,而字符流使用的数组是字符数组char[] chs。
将上个程序的try语句块中的程序改为下面这些,使用字符流的方式来读取文件。
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.FileReader; public class ReadFileTest { public static void main(String[] args){ try{ FileReader file = new FileReader("C:/Users/Administrator/Desktop/Test.txt"); //声明一个文件输入流file,并指明该文件在系统中的路径以方便定位 int data = 0; //声明一个整型变量用于存放读取的数据 while((data=file.read())!=-1){ //在while循环中使用read()方法持续读取file,数据赋到data中 //如果读取失败或者结束,则将返回-1,这个特殊的返回值可以作为读取结束的标识 System.out.print((char)data); //输出读取到数据 } file.close(); //一定要记得读取结束后要关闭文件 }catch(FileNotFoundException e){ e.printStackTrace(); }catch(IOException e){ e.printStackTrace(); } } }
上述运行结果为a,这是因为我们在输出前进行了强制类型转换。
2.3 使用FileOutputStream写入文件
import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class WriteFileTest { public static void main(String[] args) { try { String path = "C:/Users/Administrator/Desktop/newfile.txt"; //这一次我们提前声明一个字符串用于存放待写入文件的路径 String content = "i love you"; //声明一个字符串存放待写入的内容 FileOutputStream file = new FileOutputStream(path); //声明一个文件输出流对象,并指定路径 file.write(content.getBytes()); //通过write()方法将数据写入到文件中 //getBytes()方法是将字符串转化为二进制序列 file.close(); //记得关闭文件 System.out.println("File created successfully."); //提示用户创建成功 } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
将会在桌面上看到一个新建的文本文档。