IO作用:解决设备和设备之间数据传输问题,内存->硬盘,硬盘->内存,键盘数据->内存
数据存到硬盘上,就做到了永久保存,数据一般是以文件形式保存到硬盘上,sun用File描述文件文件夹
File类的构造方法
new File(String pathname);
通过将给定路径来创建一个新File实例。
new File(String parent, String child); 根据parent路径名字符串和child路径名创建一个新File实例。
new File(File parent, String child); 根据parent抽象路径名和child路径名创建一个新File实例。
File类的常用方法
关于路径
windows下级用"\"
linux下级用“/”
File类常用方法
创建:
createNewFile() 在指定位置创建一个空文件,成功就返回true,如果已存在就不创建然后返回false
mkdir() 在指定位置创建目录,这只会创建最后一级目录,如果上级目录不存在就抛异常。
mkdirs() 在指定位置创建目录,这会创建路径中所有不存在的目录。
renameTo(File dest) 重命名文件或文件夹,也可以操作非空的文件夹,文件不同时相当于文件的剪切,剪切时候不能操作非空的文件夹。移动/重命名成功则返回true,失败则返回false。
renameTo()重命名,如果源文件和目标文件在同一级下,作用是重命名,如果目标文件和源文件不是在同一文件夹下,作用是剪切,且不能操作文件夹
删除:
delete() 删除文件或一个空文件夹,如果是文件夹且不为空,则不能删除,成功返回true,失败返回false。
判断:
exists() 文件或文件夹是否存在。
isFile() 是否是一个文件,如果不存在,则始终为false。
isDirectory() 是否是一个目录,如果不存在,则始终为false。
isHidden() 是否是一个隐藏的文件或是否是隐藏的目录。
isAbsolute() 测试此抽象路径名是否为绝对路径名。
获取:
getName() 获取文件或文件夹的名称,不包含上级路径。
getPath() 返回绝对路径
getAbsolutePath() 获取文件的绝对路径,与文件是否存在没关系
length() 获取文件的大小(字节数),如果文件不存在则返回0L,如果是文件夹也返回0L。
getParent() 返回此抽象路径名父目录的路径名字符串;如果此路径名没有指定父目录,则返回null。
lastModified() 获取最后一次被修改的时间。
文件夹相关:
staic File[] listRoots() 列出所有的根目录(Window中就是所有系统的盘符)
list() 返回目录下的文件或者目录名,包含隐藏文件。对于文件这样操作会返回null。
list(FilenameFilter filter) 返回指定当前目录中符合过滤条件的子文件或子目录。对于文件这样操作会返回null。
listFiles() 返回目录下的文件或者目录对象(File类实例),包含隐藏文件。对于文件这样操作会返回null。
listFiles(FilenameFilter filter) 返回指定当前目录中符合过滤条件的子文件或子目录。对于文件这样操作会返回null。
流的分类
1、按方向
输入流
输出流
2、按处理单位
字节流
就是用于读取文件的字节数据,读取到的数据不会进行任何处理
字符流
读取到的字节数据会转成读得懂的字符数据,读取的是以字符为单位 字符流=字节流+解码
InputStream抽象类输入字节流
FileInputStream读取文件数据的输入字节流
使用FileInputStream读取文件数据
//方式1 无法完整读取文件数据
public static void read1(){
//1、找到目标文件
File file = new File("f:\\a.txt");
FileInputStream fileInputStream = null;
try {
//2、建立数据的输入通道
fileInputStream = new FileInputStream(file);
//3、读取文件数据
int content = fileInputStream.read();//返回的是读取的数据,没辞职会读取一个字节
System.out.println("读到的内容"+(char)content);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//4、关闭资源(释放资源文件)
try {
fileInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//方式2 每次可以读一个字节数据,可以完整读取数据
public static void read2(){
//1、找到目标文件
File file = new File("f:\\a.txt");
FileInputStream fileInputStream = null;
try {
//2、建立数据的输入通道
fileInputStream = new FileInputStream(file);
//3、读取文件数据
int content = 0;//用于保存读到的数据
while((content = fileInputStream.read()) != -1){//read()方法如果读到-1,表示结束
System.out.print((char)content);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//4、关闭资源(释放资源文件)
try {
fileInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
但是方式2的效率又不高,就像你给全班同学买水,每次买一瓶
//方式3 使用字节数组
public static void read3(){
//1、找到目标文件
File file = new File("f:\\a.txt");
FileInputStream fileInputStream = null;
try {
//2、建立数据的输入通道
fileInputStream = new FileInputStream(file);
//3、读取文件数据
byte[] buf = new byte[1024];
int length = fileInputStream.read(buf);//先把读取到的数据存储到字节数组中,然后返回本次读取到的字节数
System.out.println("新生成的字符串"+new String(buf,0,length));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//4、关闭资源(释放资源文件)
try {
fileInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
如果文件够大,法三也不好
//方式4 使用循环配合缓冲读取数据
public static void read4(){
//1、找到目标文件
File file = new File("f:\\a.txt");
FileInputStream fileInputStream = null;
try {
//2、建立数据的输入通道
fileInputStream = new FileInputStream(file);
//3、读取文件数据
byte[] buf = new byte[1024];//缓冲字节数组越大效率越高,一般都是1024的倍数
int length = 0;//记录本次读字节个数
while((length = fileInputStream.read(buf)) != -1){
System.out.print(new String(buf,0,length));
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//4、关闭资源(释放资源文件)
try {
fileInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
如果相比较运行效率,可以在程序开始前和程序开始后各定义一个startTime和endTime,即
//方式4 使用循环配合缓冲读取数据
public static void read4(){
long startTime = System.currentTimeMillis();
//1、找到目标文件
File file = new File("f:\\a.txt");
FileInputStream fileInputStream = null;
try {
//2、建立数据的输入通道
fileInputStream = new FileInputStream(file);
//3、读取文件数据
byte[] buf = new byte[1024];
int length = 0;//记录本次读字节个数
while((length = fileInputStream.read(buf)) != -1){
System.out.print(new String(buf,0,length));
}
long endTime = System.currentTimeMillis();
System.out.println(endTime-startTime);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//4、关闭资源(释放资源文件)
try {
fileInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
现在来验证一下为何要释放资源
当打断点时删除文件,会提示无法删除
OutputStream所有输出字节流的父类
FileOutputStream向输出数据的输出字节流
//方式1 每次只能写一个字节的数据
public static void write1(){
//1、找到目标文件
File file = new File("f:\\b.txt");
FileOutputStream fileOutputStream = null;
try {
//2、建立数据的输出通道
fileOutputStream = new FileOutputStream(file);
//3、把数据写出
fileOutputStream.write('h');
fileOutputStream.write('l');
fileOutputStream.write('l');
fileOutputStream.write('o');
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
fileOutputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//方式2
public static void write2(){
//1、找到目标文件
File file = new File("f:\\b.txt");
FileOutputStream fileOutputStream = null;
try {
//2、建立数据的输出通道
fileOutputStream = new FileOutputStream(file);
//3、准备数据,把数据写出
String str = "hllo";
//4、把字符串转成字节数组
byte[] buf = str.getBytes();
fileOutputStream.write(buf);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
fileOutputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
FileOutputStream要注意的细节:
1. new FileOutputStream 的时候,如果目标文件不存在,那么会先创建目标 文件,然后再写入。
2. new FileOutputStream(file) 如果目标文件已经存在,那么会先清空 目标文件的数据,然后再写入新的数据.
3. 写入数据的时候如果需要以追加的形式写入,那么需要使用new FileOutputStream(file,true) 这个构造函数。
4. 使用write(int b)方法的时候,虽然参数接受的一个int类型的数据,但是实际上只会把数据的低八位写出,其他24位丢弃。
练习 拷贝图片
public static void copyPic(){
//找到目标文件
File inFile = new File("F:\\37.jpg");
File outFile = new File("F:\\37_1.jpg");
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
try {
//建立数据通道
fileInputStream = new FileInputStream(inFile);
fileOutputStream = new FileOutputStream(outFile);
//建立缓冲字节数组,边读边写
byte[] buf = new byte[1024];
int length = 0;//记录每次读取字节个数
while((length = fileInputStream.read(buf)) != -1){//假设最后一次读了700个字节,最后数组中剩余的空间也会被拷贝
fileOutputStream.write(buf,0,length);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//原则 先开后关,后开先关
try {
fileOutputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
fileInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
由上,我们可以看出缓冲带来的效率之快,因此sun公司设计了缓冲字节流,凡是缓冲流,都会以Buffered开头
BufferedInputStream 缓冲输入字节流 该类本质就是在类内部维护了大小为8kb的字节数组,凡是缓冲流都没有读写文件的能力,BuffereInputStream 的close方法实际上关闭的就是你传递进去的FileInputStream对象。
public static void buffer1(){
//1、找到目标文件
File file = new File("f:\\b.txt");
FileInputStream fileInputStream = null;
BufferedInputStream bufferedInputStream = null;
try {
//2、建立数据的输入通道
fileInputStream = new FileInputStream(file);
//3、建立缓冲输入字节流
bufferedInputStream = new BufferedInputStream(fileInputStream);
int content = 0;
while((content = bufferedInputStream.read()) != -1){
System.out.print((char)content);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
bufferedInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
BufferedOutputStream 缓冲输出流,为了提高写文件的效率
public static void buffer2(){
//1、找到目标文件
File file = new File("f:\\b.txt");
FileOutputStream fileOutputStream = null;
BufferedOutputStream bufferedOutputStream = null;
try {
//2、建立数据的输出通道
fileOutputStream = new FileOutputStream(file);
//3、建立缓冲输出字节流
bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
//4、写数据
String str = "hello world";
bufferedOutputStream.write(str.getBytes());
bufferedOutputStream.flush();//把缓冲字节数组的数据写到硬盘中
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
bufferedOutputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
BufferedOutputStream 需要注意的事项: BufferedInputStream
1. 使用BufferedOutputStream的write方法时候,数据其实是写入了BufferedOutputStream内部维护的字节数组中,只有你调用
BufferedOutputStream的close方法或者是flush方法数据才会真正的写到硬盘上去或者内部维护的字节数组已经存储满数据了,这时候
数据也会写到硬盘上去。
2/. BufferedOutputStream 的close方法实际上关闭的就是你传入的OutputStream对象的close方法。
练习 利用缓冲输入输出字节流拷贝图片
public static void copyPic1(){
File inFile = new File("F:\\37.jpg");
File outFile = new File("F:\\37_2.jpg");
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
BufferedInputStream bufferedInputStream = null;
BufferedOutputStream bufferedOutputStream = null;
try {
fileInputStream = new FileInputStream(inFile);
fileOutputStream = new FileOutputStream(outFile);
bufferedInputStream = new BufferedInputStream(fileInputStream);
bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
int content = 0;
while((content = bufferedInputStream.read()) != -1){
bufferedOutputStream.write(content);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
bufferedOutputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
bufferedInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
这里提一下,不需要每次循环都flush一下,可以用前后执行时间比对,会发现不加flush速度更快
字符流
向文件中写入中文
public static void chineseWrite(){
File file = new File("F:\\b.txt");
String str = "今晚好";
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(file);
fileOutputStream.write(str.getBytes());
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
因为写字节流时字节流不具备编码和解码格式的限制,因此写中文不会乱码,但是,读取文件中数据会如何?
public static void chineseRead(){
File file = new File("F:\\b.txt");
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(file);
int content = 0;
while((content = fileInputStream.read()) != -1){
System.out.print((char)content);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
会发现乱码,因为一个汉字有两个字节构成,而以上的读法每次只读一个字节
public static void chineseRead(){
File file = new File("F:\\b.txt");
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(file);
int length = 0;
byte[] buf = new byte[2];
while((length = fileInputStream.read(buf)) != -1){
System.out.print(new String(buf,0,length));
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
可以看出非常麻烦,因此引出字符流,字符流是指读取的数据是以字符为单位的,会把读到的字节数据转换成我们看的字符,字符流 = 字节流+编码(解码)
输入字符流
Reader 抽象类 所有输入字符流的基类
FileReader 读取文件数据的输入字符流
//法1 每次只会读取一个字符数据
public static void readTest1(){
//1、找到目标对象
File file = new File("F:\\b.txt");
FileReader fileReader = null;
try {
//2、建立数据的输入通道
fileReader = new FileReader(file);
//3、读取文件数据
int content = 0;
while((content = fileReader.read()) != -1){//FileReader的read方法每次读取一个字符的数据,如果读到文件结束,返回-1
System.out.print((char)content);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//法2 使用缓冲字符数组读取文件数据
public static void readTest2(){
//1、找到目标对象
File file = new File("F:\\b.txt");
FileReader fileReader = null;
try {
//2、建立数据的输入通道
fileReader = new FileReader(file);
//3、建立字符数组读取数据
char[] cbuf = new char[1024];
int length = 0;
while((length = fileReader.read(cbuf)) != -1){
System.out.print(new String(cbuf,0,length));
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
输出字符流
Writer抽象类 输出字符流的基类
FileWriter 向文件写出数据输出字符流
public static void writeTest1(){
//1、找到目标对象
File file = new File("F:\\b.txt");
FileWriter fileWriter = null;
try {
//2、建立数据输出通道
fileWriter = new FileWriter(file);
//3、准备数据
String str = "现在雨停了";
fileWriter.write(str);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
fileWriter.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
FileWriter 要注意的事项:
1. new FileWriter(file)的时候 , 如果目标文件不存在,那么会创建目标文件对象, 如果目标文件已经存在了,那么则不再重新创建。
2. 使用new FileWriter(file) 这个构造方法的时候,默认是会先清空文本的数据,然后再写入新的数据。如果需要追加数据则需要使用 new FileWriter(file,true)这个构造方法。
3. 使用FileWriter的write方法的时候,数据是写入了FileWriter内部维护的字符数组中,如果需要把数据真正的写到硬盘上去,需要调用flush方法或者 是close方法
或者是内部维护的字符数组已经满了,这时候也会写到硬盘上。