File class
在Java中,class File是java用来处理文件的对象。它的使用一般是
File file = new File("e://");
// File e = new File("absolutePath");
//获取file1的父路径,在该路径下创建一个名为newFile的文件夹
File f = new File(file1.getParentFile(), "newFile");
//File f = new File(String parent, String child);
//意思是在parent这个路径下,创建一个名为child的文件或者文件夹
文件File类可以不关闭,但是IO一定要关闭!!!
如果指定的路径是具体文件的名字,比如new File(“e://a.txt”) 那么就只会打开一个文件。如果设定的是一个路径,那么file会一次性全部读取路径下的所有文件,可以使用 .listFiles() 然后遍历。贴一段代码,代码目的是输出所有文件结尾是avi且文件大小大于100MB的
public class Demo4 {
public static void main(String[] args) {
File e = new File("e://");
File[] files = e.listFiles();
//调用自己写的listFile来操作
listFile(files);
}
public static void listFile(File[] files){
//这个一定要加,防止文件操作空指针
if(files!=null&&files.length>0){
//foreach循环File[]数组
for (File file:files) {
//如果是文件,进行.avi判定
if(file.isFile()){
if(file.getName().endsWith(".avi")){
//要求文件大小大于100MB
if(file.length()>100*1024*1024)
System.out.println("找到了一个avi文件"+file.getAbsolutePath());
}
//如果是文件夹则进行文件夹内部循环。
//文件夹判定为file.isDirectory();
}else {
File[] files2 = file.listFiles();
listFile(files2);
}
}
}
}
}
IO
1. IO 概述
可以将这种数据传输操作,看做一种数据的流动 , 按照流动的方向分为输入Input和输出Output
Java中的IO操作主要指的是 java.io包下的一些常用类的使用. 通过这些常用类对数据进行读取(输入Input) 和 写出(输出Output)
IO流的分类:
按照流的方向来分,可以分为:输入流和输出流.
按照流动的数据类型来分,可以分为:字节流和字符流
字节流:(操作中文会乱码)
- 输入流 : InputStream
- 输出流 : OutputStream
字符流:
- 输入流 : Reader
- 输出流 : Writer
1字符 = 2字节
1字节 = 1byte = 8bit
一切皆字节:
计算机中的任何数据(文本,图片,视频,音乐等等)都是以二进制的形式存储的.
在数据传输时 也都是以二进制的形式存储的.
后续学习的任何流 , 在传输时底层都是二进制.
流操作完必须关闭!!!!!!!!!!!
2. 字节流操作
字节流用的比较多,因为它可以操作任何文件。但是字符流对于操作String会比较好用,因为它自带方法,且按照字符读取
2.1 OutputStream
这是个抽象类,常见用法如下:
2.1 常用子类 FileOutputStream
这是OutputStream最常见的子类,调用结束一定要执行close()
// 这里要注意!你的方法一定要throws IOException,
// 因为有的时候创建是会失败的,这个下面说。
// 1. 使用字符串指定文件名称
//FileOutputStream fos = new FileOutputStream(String name);
FileOutputStream fos = new FileOutputStream("c://a.txt");
// 2. 使用字符串指定文件名称,并且写入采用的是追加方式
//FileOutputStream fos = new FileOutputStream(String name, boolean flag);
FileOutputStream fos = new FileOutputStream("c://a.txt", true);
// 3. 创建输出流,并指定将要输出到的文件
//FileOutputStream fos = new FileOutputStream(File file);
FileOutputStream fos = new FileOutputStream(file);
// 3. 创建输出流,并指定将要输出到的文件。写入方式为追加模式。
//FileOutputStream fos = new FileOutputStream(File file, boolean flag);
FileOutputStream fos = new FileOutputStream(file, true);
接下来写一个例子,这个例子里有如何输入,输入格式以及效果
注意在下面的main方法后面加了throws IOException!
public class OutputStreamDemo {
//OutputStream
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("c://a.txt");
fos.write(65); //这里写入文本的是A
byte[] bytes = "123".getBytes(); //这里写入文本的是123
fos.write(bytes);
}
}
fos.write()括号内只能输入int/ byte[]/ (byte[], int start, int len)
第三个是只从bytes数组中的start下标开始读,读len个。
注意这里的输出第一个是A,第二个是123。因为这里输入的int是按照ASCII转换的字符,所以会变成A。原因是fos只向下取低8位。(int是4字节,低八位就是最末尾的1字节,8bit,最大255,对应ASCII的255位编码,所以是64)
如果想输入固定字符,让他保持不变的话就用byte[] bytes = string.getBytes(); 这样可以保证输入。
2.2 InputStream
常用子类FileInputStream
这个和上面同理,调用结束一定要执行close()。
通常我们写的下载就是用这个,从文件中读数据。我们一般的做法都是设置一个大小的byte数组,然后每次循环读,直到读完。
这里注意一下,调用fis.read(byte[]) 这里返回的是真实读取到的byte长度,并把它赋值到bytes这个数组里。
请注意看代码里len的注释!!!
public class FISDemo {
//InputStream
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("c://a.txt");
byte[] bytes = new byte[10];
int len = 0;
while(len > -1){
//这里为什么要判断len呢?
//首先len = -1说明文件已经读到结尾了,毋庸置疑
//其次判断len的最关键的问题就是,文件的大小很可能不是你设置的bytes数组的长度的n倍
//举个例子,有26个字母,那么第三次读取的时候其实只有6个
//也就是说这6个会覆盖bytes的前6个元素,但是第二次读取的后四个
//并不受影响。因此!最后一次会多出4个!
//但是如果每次读取判定len,用new String(bytes,0,len)去读,就不会读到重复的后四位了,嘿嘿
len = fis.read(bytes);
System.out.println(new String(bytes,0,len));
}
fis.close();
}
}
注意点
字节流操作有一个很大的问题,就是遇到中文的时候。因为他是一个一个字节操作,但是对于中文来说,一个汉字三个字节,因此有的时候会读一半半。可以解决的方法是读取的长度一定大于中文的长度,但是这个往往在真实设计中难以实现。
下面举个例子,输入是“锄禾日当午”,byte[]长度是10。它读前三个用了9byte,最后一个只有1byte了,就会输出乱码。
3. 字符流
与字节流的区别是,一次性读的是一整个字符,所以比较适合字符操作。从原理上来说,毕竟万物皆字节,字符流只不过是有一个内置的缓存,一个一个读取字节,直到形成了一个字符才输出。所以字符流操作单位是char,而不是byte,进行操作的数组也是char[],而不是byte[]。
3.1 Writer
常用子类 FileWriter
使用方法基本与OutputStream一致,但是多了一个append的方法。
首先说明这个方法并不是默认文件写入格式为追加模式,就是在申明FileWriter fw的时候如果后面不是true,那么一样会直接覆盖而不是追加!
其次,这个方法的操作返回的是一个this,属于Writer类。
什么意思呢,就是说我用fw.append(“abc")之后会返回一个fw,它是添加完abc内容的。所以如果你用FileWriter fw2 = fw.append(“锄禾日当午”),那么fw2 == fw会返回true。因为在内存里指向的是同一个地址。
public class FileWriterDemo {
public static void main(String[] args) throws IOException {
//writer
FileWriter fw = new FileWriter("c://b.txt",true);
//在文件fw中不停的追加
fw.append("锄禾日当午").append(",").append("汗滴禾下土"); //可以一致追加
fw.write("锄禾日当午");
fw.flush(); //刷新
fw.close();
}
}
Reader
常用子类 FileReader
reader的注意点也和InputStream一样,首先判断是否读到文件结尾,用fr.read()方法返回的int来确定,-1即文件结尾。
这里注意一下,如果是fr.read(),那么代表我每次只读一个字符,所以返回的是字符在ASCII里转换成数字的值。
如果是fr.read(byte[] bytes),那么意思是我将读到的内容尽可能填满byte数组。那么返回的是改次读取的长度。
注意下面读取的数组是char[],而不是byte[]
public class Demo10 {
public static void main(String[] args) throws IOException {
//reader
FileReader fr = new FileReader("b.txt");
char[] chars = new char[100];
while (true){
int c = fr.read(chars);
if(c==-1){
break;
}
System.out.println(new String(chars, 0, len));
}
fr.close();
}
}
4. flush()
这里提一嘴flush,一个重要的方法和概念。这个方法是强制刷新缓存区,将缓存区的内容写入文件中。其实在字符流和字节流中都存在缓存区,如果缓存区溢出那么就会直接将缓存区内容写入到文件中。而字节流的缓存区非常小,所以一般的输入都会导致溢出,就自动写入了。但是字符流的缓存区就比较大,如果不写满就无法写入到文件中。这时候就可以调用flush(),强制将缓存区内容写入文件。人为写flush()是个好习惯!并且flush()还有个好处是它可以控制实时通讯。同时close()方法会自动实现flush,所以如果文件较小可以直接close。
4. 字节流转换为字符流
给个简单的例子
基本上使用InputStreamReader读取字节流文件,还可以定义编码格式。
InputStreamReader isr = new InputStreamReader(字节流, String 编码格式);
public static void main(String[] args) throws IOException {
//转换流 :将字节流转换成字符流 使用了装饰者模式
FileInputStream fis = new FileInputStream("c://a.txt");
//将字节输入流转换为字符输入流 参数为要转换的字节流
InputStreamReader isr = new InputStreamReader(fis,"gbk");
while (true){
int c = isr.read();
if(c==-1){
break;
}
System.out.println((char) c);
}
}
BufferedReader
这个类中有一个方法是readLine(),它允许一次性读一整行,不需要像前面定义一个数组或者是一个一个读,就很方便
try-with-resource
JDK 1.7时允许在try中间创建文件,避免后面写太多异常处理的冗余代码
//jdk7
try(FileReader fr = new FileReader("c://book.txt");){
int c = fr.read();
System.out.println((char)c);
}catch (IOException e) {
e.printStackTrace();
}
但是还有一个不好的地方就是,如果这个流是之前创建的,就无法进行关闭或是在try catch之后还想继续使用,也无法调用。
所以JDK 1.9 允许在try catch模块外面创建,并且在try()的括号中写入可能出错的IO流,用分号隔开
//jdk9
FileReader fr = new FileReader("c://book.txt");
PrintWriter pw = new PrintWriter("c://book.txt");
try(fr;pw){
int c = fr.read();
System.out.println((char)c);
}catch (IOException e) {
e.printStackTrace();
}