流的概念
程序中的输入输出都是以流的形式保存的,流中保存的实际都是字节文件
字节流与字符流
内容操作就四个类:OutputStream、InputStream、Writer、Reader
操作流程
使用File类操作的时候一定要有路径,请注意分隔符。
实际上四个操作类都是抽象类
IO操作属于资源操作,对于资源操作,最后必须关闭,否则可能出现位置的错误
字节流
Byte是字节,肯定使用字节流操作,所有的数据基本上都可以直接使用Byte数组表示出来。
字节输出流:OutputStream
Clonseable表示关闭的操作,因为程序运行最后肯定要关闭。
Flush表示刷新,清空内存中的数据。
OutputStream类的常用方法
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class OutputStreamDemo01 {
public static void main(String[] args) throws Exception{ //抛出异常不处理
//第一步,使用File类找到一个文件
File f = new File("d:" + File.separator + "test.txt"); //声明File对象
//第二步,通过子类实例化父类对象
OutputStream out = null;
out = new FileOutputStream(f);
//第三步,进行写操作
String str = "Hello world"; //准备一个字符串
byte b[] = str.getBytes(); //只能输出byte数组,所以将字符串变为byte数组
out.write(b);
//第四步,关闭输出流
out.close();
}
}
在操作的时候,如果文件本身不存在,则会为用户创建一个文件
在操作输出流的时候,也可以使用write(int i)的方法写出数据
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class OutputStreamDemo02 {
public static void main(String[] args) throws Exception{ //抛出异常不处理
//第一步,使用File类找到一个文件
File f = new File("d:" + File.separator + "test.txt"); //声明File对象
//第二步,通过子类实例化父类对象
OutputStream out = null;
out = new FileOutputStream(f);
//第三步,进行写操作
String str = "Hello world"; //准备一个字符串
byte b[] = str.getBytes(); //只能输出byte数组,所以将字符串变为byte数组
for(int i = 0;i < b.length;i++) {
out.write(i);
}
//第四步,关闭输出流
out.close();
}
}
在以上的操作在写入数据之后,文件之前的内容已经不存在了,因为IO操作默认的情况是将其进行覆盖,那么现在如果想要执行追加的功能,则必须设置追加的操作,找到FileOutputStream类。
追加新内容
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class OutputStreamDemo03 {
public static void main(String[] args) throws Exception{ //抛出异常不处理
//第一步,使用File类找到一个文件
File f = new File("d:" + File.separator + "test.txt"); //声明File对象
//第二步,通过子类实例化父类对象
OutputStream out = null; //准备好一个输出的对象
out = new FileOutputStream(f,true); //此处表示在末尾追加内容
//第三步,进行写操作
String str = "Hello world"; //准备一个字符串
byte b[] = str.getBytes(); //只能输出byte数组,所以将字符串变为byte数组
for(int i = 0;i < b.length;i++) {
out.write(b[i]);
}
//第四步,关闭输出流
out.close();
}
}
程序本身是可以追加内容了,但是没有换行,是直接在末尾追加的。
如果在文件操作中想要换行的话,使用\r\n完成
字节输入流:InputStream
InputStream类的常用方法
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class InputStreamDemo01 {
public static void main(String[] args) throws Exception{ //抛出异常不处理
//第一步,使用File类找到一个文件
File f = new File("d:" + File.separator + "test.txt"); //声明File对象
//第二步,通过子类实例化父类对象
InputStream in = null; //准备好一个输入的对象
in = new FileInputStream(f); //通过对象多态性,进行实例化
//第三步,进行读操作
byte b[] = new byte[1024];
in.read(b);
//第四步,关闭输出流
in.close();
System.out.println("内容为:" + new String(b)); //把byte数组变为字符串输出
}
}
此时,内容确实已经读取进来了,但是可以发现存在的问题。
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class InputStreamDemo02 {
public static void main(String[] args) throws Exception{ //抛出异常不处理
//第一步,使用File类找到一个文件
File f = new File("d:" + File.separator + "test.txt"); //声明File对象
//第二步,通过子类实例化父类对象
InputStream in = null; //准备好一个输入的对象
in = new FileInputStream(f); //通过对象多态性,进行实例化
//第三步,进行读操作
byte b[] = new byte[1024];
int len = in.read(b);
//第四步,关闭输出流
in.close();
System.out.println("读取内容的长度:" + len);
System.out.println("内容为:" + new String(b,0,len)); //把byte数组变为字符串输出
}
}
代码还是存在问题,现在文件没有这么大,但是开辟了这么大的数组空间,这样一定会浪费空间,能不能根据文件的大小开辟数组空间呢?
如果想要知道文件大小,直接使用File类即可。
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class InputStreamDemo03 {
public static void main(String[] args) throws Exception{ //抛出异常不处理
//第一步,使用File类找到一个文件
File f = new File("d:" + File.separator + "test.txt"); //声明File对象
//第二步,通过子类实例化父类对象
InputStream in = null; //准备好一个输入的对象
in = new FileInputStream(f); //通过对象多态性,进行实例化
//第三步,进行读操作
byte b[] = new byte[(int)f.length()]; //数组的大小由文件决定
int len = in.read(b);
//第四步,关闭输出流
in.close();
System.out.println("读取内容的长度:" + len);
System.out.println("内容为:" + new String(b,0,len)); //把byte数组变为字符串输出
}
}
以上直接使用byte数组的方式完成的
现在使用read方法读取内容。
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class InputStreamDemo04 {
public static void main(String[] args) throws Exception{ //抛出异常不处理
//第一步,使用File类找到一个文件
File f = new File(“d:” + File.separator + “test.txt”); //声明File对象
//第二步,通过子类实例化父类对象
InputStream in = null; //准备好一个输入的对象
in = new FileInputStream(f); //通过对象多态性,进行实例化
//第三步,进行读操作
byte b[] = new byte[(int)f.length()]; //数组的大小由文件决定
for(int i = 0;i < b.length;i++) {
b[i] = (byte)in.read(); //读取内容
}
int len = in.read(b);
//第四步,关闭输出流
in.close();
System.out.println("读取内容的长度:" + len);
System.out.println("内容为:" + new String(b)); //把byte数组变为字符串输出
}
}
以上的操作,只适合于知道输入流的大小的时候。如果不知道大小呢?
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class InputStreamDemo04 {
public static void main(String[] args) throws Exception{ //抛出异常不处理
//第一步,使用File类找到一个文件
File f = new File(“d:” + File.separator + “test.txt”); //声明File对象
//第二步,通过子类实例化父类对象
InputStream in = null; //准备好一个输入的对象
in = new FileInputStream(f); //通过对象多态性,进行实例化
//第三步,进行读操作
byte b[] = new byte[1024]; //数组的大小由文件决定
int len = 0;
int temp = 0; //接受每一个读进来的数据
while((temp=in.read()) != -1) {
//表示还有内容,文件没有读完
b[len] = (byte)temp;
len++;
}
//第四步,关闭输出流
in.close();
System.out.println("读取内容的长度:" + len);
System.out.println("内容为:" + new String(b,0,len)); //把byte数组变为字符串输出
}
}
当不知道读取内容有多大的时候,就只能以读取的数据是否为-1为读完的标志。
字符流
字符输入流:Write类
Write类常用的方法
字符流的操作比字节流操作好一些,就是可以直接输出字符串了,不用再像之前那样进行转换操作。
import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
public class WriteDemo01 {
public static void main(String[] args) throws Exception{ //抛出异常不处理
//第一步,使用File类找到一个文件
File f = new File("d:" + File.separator + "test.txt"); //声明File对象
//第二步,通过子类实例化父类对象
Writer out = null;
out = new FileWriter(f);
//第三步,进行写操作
String str = "Hello world"; //准备一个字符串
out.write(str);
//第四步,关闭输出流
out.close();
}
}
使用字节流默认情况下依然是覆盖已经有的文件,如果想要追加的话,则直接在FileWriter上增加一个可追加标记即可。
字符输入流:Reader类
Reader类的常用方法
以字符数组的形式读取数据
import java.io.File;
import java.io.FileReader;
import java.io.Reader;
public class ReaderDemo01 {
public static void main(String[] args) throws Exception{ //抛出异常不处理
//第一步,使用File类找到一个文件
File f = new File("d:" + File.separator + "test.txt"); //声明File对象
//第二步,通过子类实例化父类对象
Reader in = null; //准备好一个输入的对象
in = new FileReader(f); //通过对象多态性,进行实例化
//第三步,进行读操作
char b[] = new char[1024];
int len = in.read(b);
//第四步,关闭输出流
in.close();
System.out.println("内容为:" + new String(b,0,len)); //把字符数组变为字符串输出
}
}
也可以使用循环方法,通过文件是否读到底的形式读取;
import java.io.File;
import java.io.FileReader;
import java.io.Reader;
public class ReaderDemo02 {
public static void main(String[] args) throws Exception{ //抛出异常不处理
//第一步,使用File类找到一个文件
File f = new File("d:" + File.separator + "test.txt"); //声明File对象
//第二步,通过子类实例化父类对象
Reader in = null; //准备好一个输入的对象
in = new FileReader(f); //通过对象多态性,进行实例化
//第三步,进行读操作
char b[] = new char[1024];
int temp = 0; //接受每个内容
int len = 0;
while((temp=in.read())!=-1) {
b[len] = (char)temp;
len++;
}
//第四步,关闭输出流
in.close();
System.out.println("内容为:" + new String(b,0,len)); //把字符数组变为字符串输出
}
}
字节流与字符流的区别
字节流和字符流的使用是非常相似的,那么除了操作代码的不同之外,还有那些不同呢?
通过一个代码验证字符流使用到了缓存。
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class OutputStreamDemo05 {
public static void main(String[] args) throws Exception{ //抛出异常不处理
//第一步,使用File类找到一个文件
File f = new File("d:" + File.separator + "test.txt"); //声明File对象
//第二步,通过子类实例化父类对象
OutputStream out = null; //准备好一个输出的对象
out = new FileOutputStream(f); //实例化
//第三步,进行写操作
String str = "Hello world"; //准备一个字符串
byte b[] = str.getBytes(); //只能输出byte数组,所以将字符串变为byte数组
out.write(b);
}
}
在使用字节流操作中,及时没有关闭,最终也是可以输出的。
import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
public class WriteDemo03 {
public static void main(String[] args) throws Exception{ //抛出异常不处理
//第一步,使用File类找到一个文件
File f = new File("d:" + File.separator + "test.txt"); //声明File对象
//第二步,通过子类实例化父类对象
Writer out = null;
out = new FileWriter(f);
//第三步,进行写操作
String str = "Hello world"; //准备一个字符串
out.write(str);
}
}
以上的操作,没有输出任何的内容出来,也就是说,所有的内容都是保存在了缓存区中,而如果执行关闭的时候会强制性的刷新缓冲区,所以可以把内容输出。
如果现在假设没有关闭的话,可以强制调用刷新方法 。
import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
public class WriteDemo04 {
public static void main(String[] args) throws Exception{ //抛出异常不处理
//第一步,使用File类找到一个文件
File f = new File("d:" + File.separator + "test.txt"); //声明File对象
//第二步,通过子类实例化父类对象
Writer out = null;
out = new FileWriter(f);
//第三步,进行写操作
String str = "Hello world"; //准备一个字符串
out.write(str);
//强制性清空缓存区中的内容
out.flush();
}
}
问题:
开发中是使用字节流好还是字符流好
在所有的硬盘上保存文件或是进行传输的时候都是以字节的方式进行的。包括图片也是按字节完成,而字符是只有在内存中才会形成的,所以使用字节的操作是最多的。
操作范例
操作的时候可以按照如下的格式进行
javaCopy源文件
如果要采用以上的格式,则肯定要使用初始化参数的形式,输入两个路径,所以,此时就必须对输入参数的个数进行验证,判断是否为2
是使用字节流还是字符流呢?肯定使用字节流,因为万一拷贝的是一个图片。
要完成拷贝程序,有两种方式可以采用
实现1:将源文件中的内容全部读取进来,之后一次性写入到目标文件
实现2:边读边写的方式
很明显使用第二种方式