输入和输出(I/O)处理(一)
前言
在前期的学习中的存储容器演变顺序为:变量 - > 数组 -> 对象 - > 对象数组 - >集合。
通过会议这些存储容器,我们能够分析出,随着业务的发展,对存储容器的存储负责度和存储方便性等要求越来越高。
但是截至到现在,我们所学的存储技术,都无法实现持久化存储,因为它们的存储都是在计算机内存中(RAM),如果想实现将数据进行持久化存储,那么必然要先接触一下文件和IO的概念。
1. 掌握File类的常用API
文件的概念:相关记录或者放在一起的数据的集合。 它是需要储存在"长期储存"的设备上的,有了它我们就可以实现持久化存储。
java.io.File类:可以实现对文件(File)/文件夹(目录directory)的操作。
构造方法
- File(String pathname) 直接根据字符串类型地址获取对应的文件对象
// 1.File(String pathname)
File file = new File("d:/a.txt");
File file = new File("d:\\a.txt");
- File(String parent,String child) 根据字符串类型的父路径和子路径获取对应的文件对象
// 2.File(String parent父路径,String child子路径)
// 通常应用于:你已经获取到了某个文件的父路径 然后只需要通过本构造即可实现路径自动拼接
File file = new File("d:", "a.txt");
- File(File parent,String child) 根据文件类型的父路径和字符串类型的子路径获取对应的文件对象
// 3.File(File parent,String child)
// 通常应用于:你已经获取到了某个文件的父路径(File对象型的)....
File parent = new File("d:");
File file = new File(parent , "a.txt");
普通方法
-
获取文件的字节数:long length()
-
判断文件/文件夹是否存在:boolean exists();
-
判断是否是文件:boolean isFile();
-
判断是否是文件夹:boolean isDirectory();
-
获取相对路径:String getPath(); // 可以理解为 File构造传入什么路径 就得到什么路径
-
获取绝对路径:String getAbsolutepath(); // 如果File构造传入的是相对路径 则可以根据它找到对应的绝对路径,但是如果本身就是绝对路径 则直接显示。
-
创建文件:boolean createNewFile();
-
创建文件夹:boolean mkdir();
-
删除文件/空文件夹:boolean delete();
-
获取文件名称:String getName();
-
获取文件夹的子目录:File[] listFiles();
普通方法的展示代码:
public class FileTest{
public static void main(String[] args) throws IOException {
/**
* 尽量使用相对路径
* 在eclipse中,"." 当前目录,指的是项目的根目录。
*
*/
File file = new File("."+File.separator+"FileDir"+File.separator+"test.txt");
// 获取文件属性
String name = file.getName();
System.out.println("name:"+name);
/**
* 获取大小
* 返回值为一个long值,表示占用的字节量
*/
long length = file.length();
System.out.println("l:"+length);
// 判断是否可运行,可读,可写 权限 返回boolean值
System.out.println(file.canExecute());
System.out.println(file.canRead());
System.out.println(file.canWrite());
// 判断当前File对象表示的是否为一个文件
boolean isFile = file.isFile();
System.out.println("isFile:"+isFile);
// 是否是文件夹
boolean isDir = file.isDirectory();
System.out.println("isDir:"+isDir);
// 创建文件
File file2 = new File("."+File.separator+"FileDir"+File.separator+"creat.txt");
if(!file2.exists()){
file2.createNewFile();
System.out.println("文件creat.txt创建成功");
}
// 删除文件
File file3 = new File("."+File.separator+"FileDir"+File.separator+"del.txt");
if(file3.exists()){
file3.delete();
System.out.println("删除del文件成功!");
}
// 创建目录
File dir = new File("."+File.separator+"FileDir"+File.separator+"aa");
if(!dir.exists()){
dir.mkdir();
System.out.println("创建aa目录成功!");
}
// 创建多级目录
File dir2 = new File("."+File.separator+"FileDir"+File.separator
+"aa"+File.separator+"c"+File.separator+"d");
if(!dir2.exists()){
dir2.mkdirs();
System.out.println("make dirs");
}
// 删除目录 删除目录,只能删除空目录
File dir3 = new File("."+File.separator+"FileDir"+File.separator
+"aa"+File.separator+"c"+File.separator+"d");
if(dir3.exists()){
dir3.delete();
System.out.println("删除d目录");
}
// 获取一个目录下的所有子项
File dir4 = new File("."+File.separator+"FileDir");
File [] files = dir4.listFiles();
for(File f : files){
System.out.println((f.isFile() ? "文件:" :"目录:")+f.getName());
}
// 获取过滤之后的文件
File dir5 = new File("."+File.separator+"FileDir");
File [] fs = dir4.listFiles(new FileFilter() {
public boolean accept(File file) {
System.out.println("正在过滤:"+file.getName());
return file.getName().startsWith("t");
}
});
for(File f : fs){
System.out.println("t开头的文件有:"+f.getName());
}
// 递归删除目录所有文件
File dir6 = new File("."+File.separator+"FileDir"+File.separator+"b");
deleteFile(dir6);
}
// 递归删除文件
public static void deleteFile(File file){
if(file.isDirectory()){
File[] files = file.listFiles();
for(File f : files){
deleteFile(f);
}
}
file.delete();
}
}
2. 掌握流的概念和分类
I/O流的概念
java的io是实现输入和输出的基础,可以方便的实现数据的输入和输出操作。在java中把不同的输入/输出源(键盘,文件,网络连接等)抽象表述为“流”(stream)。通过流的形式允许java程序使用相同的方式来访问不同的输入/输出源。stram是从起源(source)到接收的(sink)的有序数据。
注:java把所有的传统的流类型都放到在java io包下,用于实现输入和输出功能。
流的分类
-
按照方向性分类:
输入流:读 InputStream Reader 输出流:写 OutputStream Writer
-
按照处理单元:
字节流:可以用来传输一切内容。音频、视频、图片、文本..... 根据美国ASCII码进行通信传输的 字节输入流InputStream 字节输出流OutputStream 字符流:可以用来传输文本内容 根据不同国家进行了相应文字转换(它是基于字节流产生的) 字符输入流Reader 字符输出流Writer
字符流视图
基类是抽象类无法创建对象,所以需要寻找对应的子类。
- FileInputStream
- FileOutputStream
I/O流的详细分布图:
3. 掌握使用字节流实现文件复制
字节输入流FileInputStream
构造:
- FileInputStream(File file);
- FileInputStream(String pathname);
常用方法:
- 读取一个字节数据:int read();
- 读取一个字节数组长度的字节数据 返回实际读取到的字节数量:int read(byte[] b);
- 读取输入流中从指定索引开始,指定长度的字节数据到字节数组中:int read(byte b,int offs,int len);
- 关流:void colse();
字节输出流FileOutputStream
构造:
- FileOutputStream(File file);
- FileOutputStream(String path);
- FileOutputStream(File/String file,boolean append); // 如果为true表示可以追加数据 而不是覆盖数据
常用方法:
- void write(int b); 输出一个字节
- void write(byte[] b); 输出一个字节数组的内容
- void write(byte[] b,int offs,int len); 输出一个字节数组中的指定范围的内容
- void close(); 关流
- void flush(); 强制将缓冲区清空
案例:文件的复制
/**
* 实现文件复制 将d:/a.txt 复制到 c:/a.txt
*/
public class Test {
public static void main(String[] args) throws IOException {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
// 1.指定数据源和输出目的地
fis = new FileInputStream("d:/a.txtZ
fos = new FileOutputStream("c:/a.txt");
// 2.读取数据
// 临时存储读取到的数据
byte[] buffer = new byte[1024];
int len = 0;
while((len = fis.read(buffer)) != -1) {
// 3.写入数据 读取到多少写出去多少
fos.write(buffer,0,len);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
// 4.关流
// 先开的后关
if(fos != null) {
fos.close();
}
if(fis != null) {
fis.close();
}
}
}
}