Java I/O流复习(一)—File类、字节流、字节缓冲流
1. File类
1.1 File类作用
- 文件可认为是相关记录或放在一起的数据的集合。文件一般存放在存储介质上:硬盘、u盘、光盘、软盘、云盘等。
- java.io.File 类是专门对文件进行操作的类。(只能对文件本身进行操作,不能对文件内容操作)
- File类是“文件和目录路径名的抽象表示”。 而不是指文件的内容(IO)。路径就是字符串
- File类定义了一些与平台无关的方法操作,如:创建、删除文件和重命名等。
- Java中目录被看成是一个特殊的文件。 File.listFiles()方法可以返回目录中所有的子目录和文件。
- 在unix下路径分隔符为(/),而在windos中则是为(\),在java中可以正确的处理不同系统中的分隔符。注意:从1.5开始在java中可以统一使用(/)来作为路径分隔符。
1.2 File类的构造方法
public File(String pathname); 以pathname为路径创建File对象,如果pathname是相对路径,则是相对于Java的系统属性user.dir中的路径。(对eclipse创建的java工程来说,就是该工程的根目录。)
public File(File dir,String name);
根据f 抽象路径名和 child 路径名字符串创建一个新 File 实例。
1.3 File类文件属性
1.3.1 属性:
- public static final String separator 分隔符 存储了当前系统的名称分隔符,在 UNIX 和Mac系统上,此字段的值为 ‘/’;在 Windows 系统上,它为 ‘\’;为了程序的跨平台特性,文件的路径应该用这个属性值来代表。
- public static final char pathSeparator 存储了当前系统默认路径分割符号,在 UNIX 和Mac系统上,此字段的值为’:’,Windows系统是’;’。
1.4 使用File类对文件进行访问
方法名 | 描述 |
---|---|
public boolean canRead() | 是否可读 |
public boolean canWrite() | 是否可写 |
public boolean exists() | 文件或目录是否存在,先判断 |
public boolean isDirectory() | 是否是目录(文件夹)非目录就是文件 |
public boolean isFile() | 是否是文件(非目录) |
public boolean isHidden() | 是否是隐藏文件 |
public long lastModified() | 最后一次修改的时间,需要转换 |
public long length() | 返回文件大小,以字节为单位 |
public String getName() | 返回文件的名字(不包含路径) |
public String getPath() | 返回创建File时使用指定的路径;[^提示] |
public String getAbsolutePath() | 返回此File对象的绝对路径名 |
public File getAbsoluteFile() | 返回该文件的绝对路径的文件对象。 |
public String getParent() | 返回该文件所在的目录的路径。一般转化为绝对路径对象再使用 |
public File getParentFile() | 返回该文件所在的目录File对象。 |
[^提示]: 创建文件的时候是相对路径就返回相对路径,是绝对路径就返回绝对路径。
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请输入一个路径");
String next = sc.next();
File file = new File(next);
if (file.exists()) {
String name = file.getName();
String absolutePath = file.getAbsolutePath();
File parentFile = file.getParentFile();
parentFile.getParent();
boolean canRead = file.canRead();
boolean canWrite = file.canWrite();
long lastModified = file.lastModified();
Date date = new Date(lastModified);
System.out.println("文件名"+" "+"文件的路径"+" "+"文件目录"+" "+"是否可读"+" "+"最后一次修改时间");
System.out.println(name+" "+absolutePath+" "+parentFile+" "+canRead+" "+date.toString());
break;
}else {
System.out.println("你输入的文件不存在");
}
}
1.5 使用File类对文件进行操作
方法名 | 描述 |
---|---|
public boolean createNewFile() | 当文件不存在是,则创建一个空文件(非目录)确保文件所在目录存在,否则会抛IO异常 |
public boolean delete() | 删除文件。如果是目录必须是空目录才能删除,只删除最后一级目录 |
public boolean mkdir() | 文件夹的创建。创建此抽象路径名指定(最后一级)的目录,确保父类目录存在 |
public boolean mkdirs() | 创建此抽象路径名指定的目录,包括所有必需但不存在的父目录 |
public boolean renameTo(File dest) | 重新命名此抽象路径名表示的文件。如果是文件路径是不一样的话,就相当于剪切的功能。如果一样的话,也可以看成是重命名 |
1.6 使用File类浏览目录中的文件和子目录
方法名 | 描述 |
---|---|
public String[] list() | 返回此目录中的文件名和目录名的数组,遍历输出 |
public File[] listFiles() | 返回此目录中的文件和目录的File实例数组,文件路径。如果不是目录就输出为空 |
public File[] listFiles(FileFilter filter) | 返回此目录中满足指定过滤器的文件和目录。new FileFilter 匿名内部类 |
课堂练习:使用 递归算法 打印出目录(文件夹)中所有文件与目录(包括目录内部的文件和目录)。
``java
public class Main5 {
private static void listChilds(File f){
if (f==null)
return;
System.out.println(f.getPath());
if (f.isFile())
return;
File[] files = f.listFiles();
for (File file : files)
listChilds(file);
}
private static File file = new File(“F:\\java和HTML等”);
public static void findFile(File file) {
if (file.isDirectory()) {
File[] listFiles = file.listFiles();
if (listFiles==null||listFiles.length==0) {
return;
}else {
for (File f : listFiles) {
System.out.println(f);
if (f.isDirectory()) {
findFile(f);//递归
}
}
}
}
}
public static void main(String[] args) {
findFile(file);
}
}
2. IO概念和种类:
2.1 什么是IO流?
IO指的是 Input/Output,IO流:输入输出流。 统称为数据流。(IO Stream)
在Java程序中,对于数据的输入 / 输出操作以流的方式进行;流是从起源到接收的有序数据。JDK提供了各种各样的Stream 类,用以获取不同种类的数据;
IO流的作用就是对文件数据的读(输入)和写(输出)。
2.2 流的作用和原理?
3. IO流的种类:
3.1 输入流、输出流
- 输入流:程序可以从中读取数据的流(流入程序的流)
- 输出流:程序能向其中写入数据的流 (从程序流出的流)
3.2 字节流、字符流
- 字节流:以字节为单位传输数据的流
- 字符流:以字符为单位传输数据的流
3.3 节点流、处理流
- 节点流:用于直接操作目标设备的流
- 处理流:是对一个已存在的流的连接和封装,通过对数据的处理为程序提供更为强大、灵活的读写功能。
3.4 IO流的分类图:
4. 字节输入流:
4.1 InputStream类的常用方法
- available() 方法,获取与之关联的文件剩余可读的字节数。
int read() 方法,读取输入流。读取输入流的下一个字节,返回一个0-255之间的int类型整数。如果到达流的末端,返回-1。
int read(byte[] b) 方法,读取输入流。读取多个字节,存入字节数组b,返回实际读入的字节数。如果到达流的末端,返回-1。
int read (byte[] b, int off, int len); 方法,读取输入流。每次读取len个字节,存入字节数组b,从off下标开始存储。如果到达流的末端,返回-1。
- close() 方法,关闭当前流,释放与该流相关的资源,防止资源泄露。在带资源的try语句中将被自动调用。关闭流之后还试图读取字节,会出现IOException异常。
4.2 InputStream类的子类:文件输入流FileInputStream
FileInputStream 用于读取本地文件中的字节数据,继承自InputStream类
4.2.1 FileInputStream构造方法和常用方法
4.2.1.1构造方法
- FileInputStream(File file); 通过打开一个到实际文件的连接来创建一个
FileInputStream
,该文件通过文件系统中的File
对象file
指定。 - FileInputStream(String name); 通过打开一个到实际文件的连接来创建一个
FileInputStream
,该文件通过文件系统中的路径名name
指定。
4.2.1.2 常用方法
read() 方法,读取输入流。读取输入流的下一个字节,返回一个0-255之间的int类型整数。如果到达流的末端,返回-1。
is = new FileInputStream("test.txt"); int i; while ((i = is.read()) != -1) { System.out.println("out: " + (char)i); }
read(byte[] b) 方法,读取输入流。读取多个字节,存入字节数组b,返回实际读入的字节数。
InputStream is = null; byte[] buffer = new byte[4];//每次读取4个字节 try { is = new FileInputStream("test.txt"); is.read(buffer); System.out.println("available: " + is.available());//观察在读取的过程中,available 值。 for (byte b : buffer) { System.out.println((char)b); } }...
read (byte[] b, int off, int len); 方法,读取输入流。每次读取len个字节,存入字节数组b,从off下标开始存储。
~~~java
File file = new File("helloworld.txt"); try(InputStream is = new FileInputStream(file);){ byte[] b = new byte[10]; while (true) { int read = is.read(b, 0, 10); // 当每次读取的个数刚好是 byte[] 的长度,则可以这么简写: // int read = is.read(b); if (read == -1) { break; } String string = new String(b, 0, read); System.out.print(string); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }
~~~
close() 方法,关闭当前流,释放与该流相关的资源,防止资源泄露。在带资源的try语句中将被自动调用。关闭流之后还试图读取字节,会出现IOException异常。
skip(long n) 方法,跳过(放弃)当前流的n个字节,返回实际跳过的字节数。(了解)
5. 字节输出流:
5.1 OutputStream类的常用方法
- write (int b); 将指定的字节写入此输出流。
- write(byte[] byte); 将
b.length
个字节从指定的 byte 数组写入此输出流。 - write(byte[] byte, int off, int len); 将指定 byte 数组中从偏移量
off
开始的len
个字节写入此输出流。 - flush(); 用于清空缓存里的数据,并通知底层去进行实际的写操作。(强制把缓存区里面的数据写入到文件)
- close();关闭当前流,释放与该流相关的资源。
5.2 OuputStream类的子类:文件输出类FileOutputStream
提供了文件的基本写入能力,继承自 OuputStream类
注意:
- 如果进行写操作的文件不存在,则自动创建该文件。
- 如果文件所在的路径也不存在则报错。
5.2.1 FileOutputStream构造方法和常用方法
课堂练习一:String content = “拉萨扩大解放了as建立地方看见拉萨的肌肤绿卡时间的分绿卡时间的分利咔”;
写一个方法,接收一个字符串。将该字符串写入到File(路径自己指定)中。返回boolean
课堂练习二:编写一个方法,接受第一个FIle fromFile,接受第二参数 File toFile;
将 fromFIle 文件内容复制到 toFile 中。
一边读,一边写
5.2.1.1 构造方法
- public FileOutputStream(String name); 通过打开一个到实际文件的连接来创建一个
FileOutputStream
,该文件通过文件系统中的路径名name
指定。 - public FileOutputStream(String name,boolean append);通过打开一个到实际文件的连接来创建一个
FileOutputStream
,该文件通过文件系统中的路径名name
指定。如果第二个参数为true,则将字节写入文件末尾处,而不是写入文件开始处。 - public FileOutputStream(File file):通过打开一个到实际文件的连接来创建一个
FileOutputStream
,该文件通过文件系统中的File
对象file
指定。 - public FileOutputStream(File file,boolean append);通过打开一个到实际文件的连接来创建一个
FileOutputStream
,该文件通过文件系统中的File
对象file
指定。如果第二个参数为true,则将字节写入文件末尾处,而不是写入文件开始处。
5.2.1.1 常用方法
write (int b); 将指定的字节写入此输出流。
try { File file = new File("test.txt"); OutputStream fos = new FileOutputStream(file); byte b = 'a'; fos.write(b); fos.flush(); fos.close(); }...
结果:
write(byte[] byte); 将
b.length
个字节从指定的 byte 数组写入此输出流。try { File file = new File("test.txt"); OutputStream fos = new FileOutputStream(file); byte b[]= "abcdefg".getBytes(); fos.write(b); fos.flush(); fos.close(); }...
结果:
write(byte[] byte, int off, int len); 将指定 byte 数组中从偏移量
off
开始的len
个字节写入此输出流。try { File file = new File("test.txt"); OutputStream fos = new FileOutputStream(file); byte b[]= "abcdefg".getBytes(); fos.write(b,1,3); fos.flush(); fos.close(); }...
结果:
flush(); 用于清空缓存里的数据,并通知底层去进行实际的写操作。(强制把缓存区里面的数据写入到文件)
close();关闭当前流,释放与该流相关的资源。
6 字节缓冲流
BufferedInputStream与BufferedOutputStream分别是FilterInputStream类和FilterOutputStream类的子类,实现了装饰设计模式。提高了读写性能。
6.1字节输入缓冲流 BufferedInputStream
BufferedInputStream是带缓冲区的输入流,默认缓冲区大小是8Kb,能够减少访问磁盘的次数,提高文件读取性能;
使用方式:
try {
File file = new File("test.txt");
InputStream fos = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fos,2*1024);//2*1024设置需要的缓冲区大小
byte b[] =new byte[1024];
while (bis.read(b)!=-1) {
for (byte c : b) {
System.out.println((char)c);
}
}
bis.close();
}
6.2 字节输出缓冲流 BufferedOutputStream
BufferedOutputStream是带缓冲区的输出流,能够提高文件的写入效率。
使用方式:
try {
File file = new File("test.txt");
OutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos =new BufferedOutputStream(fos,2*1024);//2*1024设置需要的缓冲区大小
byte b = "a";
bos.write(b);
bos.flush();//带有缓冲区,所以必须刷新。
bos.close();
}...
6.3 字节缓冲输入流特有的方法(了解)
(了解)mark(int readlimit) 方法(只有BufferedInputStream才支持),在流的当前位置做个标记,参数readLimit指定这个标记的“有效期”,如果从标记处开始往后,已经获取或者跳过了readLimit个字节,那么这个标记失效,不允许再重新回到这个位置(通过reset方法)。也就是你想回头不能走得太远呀,浪子回头不一定是岸了,跳过(获取)了太多字节,标记就不再等你啦。多次调用这个方法,前面的标记会被覆盖。
如果我们在 M 处做标记,readLimit为绿色部分,当流的指针在 A 处的时候,这个标记依然有效,可是一旦指针跑到 B 处,标记就失效了。
(了解)reset() 方法(只有BufferedInputStream才支持),用于重定位到最近的标记。如果在这之前mark方法从来没被调用,或者标记已经无效,会抛出IOException。如果没有抛出这个异常,将当前位置重新定位到最近的标记位置。
InputStream is = null; try { is = new BufferedInputStream(new FileInputStream("test.txt")); is.mark(4); is.skip(2); is.reset(); System.out.println((char)is.read()); } finally { if (is != null) { is.close(); } } }
课后练习
- 写一个方法,接收一个参数String text,接受第二个参数File saveFile。将text字符串内容写入到saveFile中。返回boolean
public class SaveFile {
public static boolean Read(String text, File saveFile) {
if (text == null || "".equals(text) || saveFile == null) {
return false;
}
byte[] bytes = text.getBytes();
// File file = new File("saveFile");
try (FileOutputStream fileOutputStream = new FileOutputStream(saveFile);) {
fileOutputStream.write(bytes, 0, text.length());
return false;
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return false;
}
public static void main(String[] args) {
boolean read = Read("abcdefg", new File("a.txt"));
System.out.println(read);
}
2 编写一个方法,接受第一个参数FIle fromFile,接受第二参数 File toFile;将 fromFIle 文件内容复制到 toFile 中。
public class Main {
public static void copyFile(File formFile, File toFile) {
if (formFile.exists()) {
try (FileInputStream fileInputStream = new FileInputStream(formFile);
FileOutputStream fileOutputStream = new FileOutputStream(toFile);) {
byte[] b = new byte[1024];//以这个大小来读取
while (true) {
int read = fileInputStream.read(b);
// fileInputStream.read(b,0,b.length);
if (read == -1) {
return;
}
fileOutputStream.write(b,0, read);//指定数组b 从0开始到read的长度
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) {
copyFile(new File("a.txt"), new File("c.txt"));
}
3.从键盘输入一个关键字,在 D:盘查找文件,如果文件名中包含该关键字,则输出这个文件的绝对路径,如果都没有找到,则输出找不到相关信息。
public class Find {
public static int findFile(File file,String keyName) {
int i=0;
File[] listFiles = file.listFiles();
// String[] str = file.list();
if (listFiles.length == 0 || listFiles == null) {
return -1 ;
}
for (File f : listFiles) {
if (f.isDirectory()) {
try {
int findFile = findFile(f,keyName);
i+=findFile;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (f.getName().contains(keyName)) {
// System.out.println(f.getName());
System.out.println(f.getAbsolutePath());
}
}
return i;
}
public static void main(String[] args) {
File file = new File("D:");
Scanner scanner = new Scanner(System.in);
System.out.println("请输入关键字");
String keyName = scanner.next();
int findFile = findFile(file,keyName);
if (findFile<=0) {
System.out.println("找不到");
}
}
4.将JAVA LOGO 图片 通过鼠标右键保存到 D盘(D:\cat.jpg)中,然后使用java程序 实现:
- 剪切该图片到E盘(E:\cat.jpg)中。
再从E盘把该图片的 “一半” 复制一份到D盘中。
File file1 = new File("Letter/1.jpg");
File file2 = new File("Love/1.jpg");
try (FileInputStream fis = new FileInputStream(file2); FileOutputStream fos = new FileOutputStream(file1);) {
byte[] b = new byte[1024];
int a = 0;
while (true) {
int read = fis.read(b);
if (read == -1) {
return;
}
fos.write(b, 0, read);
a += read;
if (a >= file2.length() / 2) {// 只复制一半
break;
}
}
System.out.println("复制结束");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
在D盘指定一个目录(要求目录下面有子目录和文件(图片,文档等),子目录里面也放一些目录和文件,以此类推,可以多放几层)。然后,复制该D盘该目录下所有文件(含目录)到 E盘指定目录下 。
即:将一个目录内的所有文件(含目录) 全部复制到 另一个目录下!
public class copyAll {
public static void copyDirectory(File srcDir,File destDir) {
File[] listFiles = srcDir.listFiles();
if (listFiles==null) {
return;
}
for (File file : listFiles) {
File srcFile = file;
File destFile = new File(destDir, file.getName());//得到目标文件的路径描述
if (file.isDirectory()) {
System.out.println("正在创建目录:" + destFile);
destFile.mkdir();// 在 destDir 创建对应的目标目录
copyDirectory(srcFile, destFile);//递归,得到里面的文件
}else {
//复制文件
System.out.println("正在copy文件:从" + srcFile + "到" + destFile);
Main.copyFile(srcDir, destDir);//复制
}
}
}
public static void main(String[] args) {
File srcDir = new File("");
File destDir = new File("");
copyDirectory(srcDir, destDir);
}