在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据时要使用输入流读取数据,而当程序需要将一些数据保存起来时,就要使用输出流
输入流和输出流的关系:
在 java.io
包中流的操作主要有字节流、字符流两大类,两类都有输入和输出操作。在字符流中输出主要是使用 Writer 类完成,输入主要是使用 Reader 类完成。
以文件的操作为例,主要的操作流程为:
(1)使用 File 类打开一个文件
(2)通过字节流或字符流的子类指定输出的位置
(3)进行读/写操作
(4)关闭输入/输出
字节流主要操作 byte 类型数据,以 byte 数组为准,输出数据主要使用 OutputStream
类完成,输入使用的是 InputStream
类
一、 字节输出流:OutputStream
OutputStream 是整个 IO 包中字节输出流的最大父类,定义:
public abstract class OutputStream extends Object
implements Closeable,Flushable
可以看出OutputStream
类是一个抽象类,如果要使用此类,需要先通过子类实例化对象。
如果现在要操作的是一个文件,则可以使用 FileOutputStream 类,通过向上转型,可以为 OutputStream 实例化。
在 OutputStream 类中的主要操作方法:
1. 向文件中写入字符串
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class Root{
//异常抛出不处理
public static void main(String[] args) throws Exception{
//第1步:使用File类找到一个文件
File f = new File("D:" + File.separator + "test.txt");//声明File对象
//第2步:通过子类实例化父类对象
OutputStream out = null;//准备好一个输出的对象
out = new FileOutputStream(f);//通过对象多态性,进行实例化,这里是向上转型
//第3步:进行写操作
String str = "Hello World!!!";
byte b[] = str.getBytes();//只能输出byte数组,所以将字符串变为byte数组
out.write(b);//将内容输出,保存文件
//第4步:关闭输出流
out.close();
}
}
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
程序在实例化、写、关闭时都有异常发生,为了方便起见,需要在主方法上使用 throws
关键字抛出异常,减少 try...catch
语句
如果文件不存在则会自动创建
也可以将 byte 数组中的内容一个个写入到文件之中:
byte b[] = str.getBytes();
for(int i=0;i<b.length;i++){
out.write(b[i]);//将内容按字节输出
}
- 3
- 4
2. 追加新内容
可以通过FileOutputStream 向文件中追加内容,FileOutputStream的另一个构造方法:
public FileOutputStream(File file,boolean append) throws FileNotFoundException
- 1
在构造方法中,如果将 append 的值设置为 TRUE,表示在文件的末尾追加内容
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class Root{
//异常抛出不处理
public static void main(String[] args) throws Exception{
//第1步:使用File类找到一个文件
File f = new File("D:" + File.separator + "test.txt");//声明File对象
//第2步:通过子类实例化父类对象
OutputStream out = null;//准备好一个输出的对象
out = new FileOutputStream(f,true);//表示在文件末尾追加内容
//第3步:进行写操作
String str = "Good Morning !!!";
byte b[] = str.getBytes();//只能输出byte数组,所以将字符串变为byte数组
out.write(b);//将内容输出,保存文件
//第4步:关闭输出流
out.close();
}
}
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
如果要使用换行可以通过 \r\n
增加换行
String str = "\r\n Hello World!!!"
- 1
二、字节输入流 InputStream
既然程序可以向文件中写入内容,则可以通过 InputStream 从文件中把内容读取出来
InputStream 类定义:
public abstract class InputStream extends Object implements Closeable
- 1
与OutputStream 类一样,InputStream 也是一个抽象类,必须依靠其子类,如果现在从文件中读取,子类肯定是 FileInputStream。
1. 从文件中读取内容
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class Test{
public static void main(String[] args) throws Exception{//异常抛出不处理
//第1步:使用 File 类找到一个文件
File f = new File("D:" + File.separator + "test.txt");
// 第2步:通过子类实例化父类对象
InputStream input = null;
input = new FileInputStream(f);//通过多态进行实例化
// 第3步:进行读操作
byte b[] = new byte[1024];//将所有内容读到此数组中
input.read(b);//将内容取出,内如读到 byte 数组中
// 第4步:关闭输入流
input.close();
System.out.println("内容为:" + new String(b));//把 byte 数组变为字符串输出
}
}
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
此时由于开辟的 byte 数组大小为1024,实际内容只有14个字节所以存在多余的空白空间,造成输出的结果含有大量空格,修改如下:
byte b[] = new byte[1024];//将所有内容读到此数组中
int len = input.read(b);//将内容取出,内如读到 byte 数组中
// 第4步:关闭输入流
input.close();
System.out.println("读入数据的长度:" + len);
System.out.println("内容为:" + new String(b,0,len));//把 byte 数组变为字符串输出
- 3
- 4
- 5
- 6
此时将将byte数组中指定范围的内容变成了字符串
2. 开辟指定大小的 byte 数组
byte b[] = new byte[(int)f.length()];//将所有内容读到此数组中,数组大小由文件制定input.read(b);//将内容取出,内如读到 byte 数组中
// 第4步:关闭输入流
input.close();
System.out.println("内容为:" + new String(b));//把 byte 数组变为字符串输出
- 3
- 4
3. 通过 read() 循环读取
byte b[] = new byte[(int)f.length()];//将所有内容读到此数组中,数组大小由文件制定
for (int i=0;i<b.length;i++){
b[i] = (byte)input.read();//将内容读出
}
// 第4步:关闭输入流
input.close();
System.out.println("内容为:" + new String(b));//把 byte 数组变为字符串输出
- 3
- 4
- 5
- 6
- 7
当不知道具体数组大小时,可以通过判断是否读到文件末尾来读取文件:
// 第3步:进行读操作
byte b[] = new byte[1024];//将所有内容读到此数组中,数组大小由文件制定
int temp = 0;
int len = 0;
while ((temp = input.read())!= -1){
//将每次的读取内容给 temp 变量,如果temp的值不是 -1,则表示文件没有读完
b[len] = (byte)temp;
len++;
}
// 第4步:关闭输入流
input.close();
System.out.println("内容为:" + new String(b,0,len));//把 byte 数组变为字符串输出
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
只有当文件读到末尾时,才会返回 -1
三、文件复制
程序运行时可以按照如下格式:
java Copy 源文件 目标文件
- 1
此时想要完成将D盘中的test.txt文件复制到D盘中的 demo.txt 文件
此时要完成这样的复制程序,可以用两种方式操作:
(1)将源文件中的内容全部读取到内存,并一次性写入到目标文件中
(2)不讲源文件中的内容全部读取进来,采用边读边写的方式
很明显,第(2)种方法更好合理,因为如果内容过多,则整个内存是无法装下的,程序肯定会出现异常,而如果采用边读边写的方式,肯定比全部读进来性能高很多
import java.io.*;
public class Copy {
public static void main(String[] args) throws Exception{
if (args.length != 2) {
// 判断是否是两个参数
System.out.println("输入的参数不正确!");
System.out.println("例:java Copy 源文件路径 目标文件路径");
System.exit(1);//系统退出
}
File f1 = new File(args[0]);//源文件的 File 对象
File f2 = new File(args[1]);//目标文件的File对象
if (!f1.exists()) {
System.out.println("源文件不存在!");
System.exit(1);
}
InputStream input = new FileInputStream(f1);//准备好输入流对象,读取源文件
OutputStream out = new FileOutputStream(f2);//准备好输出流对象,写入目标文件
if (input != null && out != null) {//判断输入或输出是否准备好
int temp =0;
try{
while ((temp=input.read())!=-1){//开始复制
out.write(temp);//边读边写
}
System.out.println("复制完成");
}catch (IOException e){
e.printStackTrace();
}
input.close();
out.close();
}
}
}
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34