文件创建
调用方法:createNewFile()
这个方法会抛出一个IOException的异常
File file =
new
File(
"D:/1.txt"
);
file.createNewFile();
对于createNewFile方法它只能去创建文件,不可以创建目录
创建目录
调用方法mkdir()
File file =
new
File(
"D:/newDir"
);
file.mkdir();
创建目录时注意还有一个方法mkdirs()
mkdir与mkdirs方法的区别
mkdir:它只能创建一级的目录
mkdir:它可以创建多级的目录
File file =
new
File(
"D:/newDir/xiaoxie/proj"
);
file.mkdirs();
删除文件
调用方法delete()
File file =
new
File(
"D:/1.txt"
);
file.delete();
对于delete方法即可以删除文件也可以删除目录,但是在删除目录时有一个限制条件:
必须保证所删除的目录为空目录
如果要删除非空目录,则需要进行遍历删除
遍历删除目录的方法:
public static void delete(File dir){
//如果是目录需要删除它下面的所有文件
if(dir.isDirectory()){
//遍历它的下一级进行删除,使它成为一个空目录
File[] files = dir.listFiles();
for (File file : files) {
delete(file);
}
}
//如果是文件则直接删除,如果是目录则在上一个if块中处理完后最后做一次删除
dir.delete();
}
注意:上述的删除操作是不会到回收站当中去的,它会进行彻底的删除操作
文件重命名
调用方法renameTo(File 新文件/目录)
这个方法可以实现把一个文件或目录移动至什么位置同时可以给定它新的名称,从而实现了重命名的目的
File file =
new
File(
"D:/newDir"
);
file.renameTo(
new
File(
"D:/
资料
/haha"
));
上面这个则会把D盘下的newDir这个目录移到
D:\资料目录下并且由原来的newDir这个目录名称变更为haha
I/O流的基本介绍
关于IO流的四个基本抽象类
InputStream 字节的输入流
OutputStream 字节的输出流
Reader 字符的输入流
Writer 字符的输出流
IO流的分类
按方向分(是输入还是输出),这个是以程序为中心来讨论的
输入流:进行读的操作
输出流:进行写的操作
按数据处理的单位不同分(字符、字节)
字节流:以字节为单位,它适用于所有类型的数据
字符流:以字符为单位,它仅仅能处理字符数据(.txt、.java、.js、.html、.css、……)
按IO流的角色来分
节点流:如:文件流
处理流:如:缓冲流、编码解码IO流、序列化与反序列化流(它是在其它流【节点流和处理流】的基础上增加功能用的,它依赖于节点流,节点流才是最终要达成的目标,而处理流只是在这个达成目标过程中做的一些功能增强)
IO流的设计用到了装饰者设计模式
如读取一个文件
文件输入流(节点流) + 缓冲流(处理流) + 反序列化流(处理流)
常见的IO流
分类
|
类型
|
说明
|
备注
|
文件相关IO流
| FileInputStream |
文件字节的输入流
|
读取任意类型的文件
|
File
OutputStream
|
文件字节的输出流
|
可以把数据写到任意类型的文件
| |
FileR
eader
|
文件字符的输入流
|
只能读取纯文本文件
| |
File
Writer
|
文件字符的输出流
|
只能把数据写到纯文本的文件
| |
缓冲流
|
Buffered
InputStream
|
字节缓冲的输入流
|
给InputStream系列的IO流增加缓冲功能
|
Buffered
OutputStream
|
字节缓冲的输出流
|
给OutputStream系列的IO流增加缓冲功能
| |
Buffered
R
eader
|
字符缓冲的输入流
|
给Reader系列的IO流增加缓冲功能
| |
Buffered
Writer
|
字符缓冲的输出流
|
给Writer系列的IO流增加缓冲功能
| |
数据IO流
|
DataInputStream
|
数据字节输入流
|
|
DataOutputStream
|
数据字节输出流
|
| |
字符串IO流
|
StringReader
|
字符串输入流
|
|
StringWriter
|
字符串输出流
|
| |
数组IO流
|
ByteArrayInputStream
|
从byte[]数组中读取
|
|
ByteArrayOutputStram
|
写到byte[]数组
|
| |
CharArrayReader
|
从char[]数组中读取
|
| |
CharArrayWriter
|
写入char[]数组
|
| |
对象IO流
|
ObjectInputStream
|
对象字节输入流
|
反序列化(反序列化就是把字节序列解析为java对象)
|
ObjectOutputStram
|
对象字节输出流
|
序列化(序列化的意思就是把java对象转为字节序列)
| |
打印流
|
PrintStream
|
字节输出
|
|
PrintWriter
|
字符输出
|
|
IO流的基本使用
IO流相关的程序的编码步骤
1. 选择一个合适的IO流类型
比如:我们要读取一个文件,那么第一,想到我们需要使用文件相关的流;第二,读相关流
FileInputStream、FileReader 框定了这两个后再细看是否为纯文本的,如果是则可以使用FileReader,从而确定具体要使用的那个类型
2.调用合适的方法,读:read系列;写:write系列
-
关闭IO流,在流使用完成后要关闭流
读取文件的操作(编码步骤的框架测试)
public void testReadFile(){
try {
//选择合适的IO流类型,并创建对象
FileInputStream fis = new FileInputStream("D:/a.txt");
//读取文件
int read = fis.read();
System.out.println(read);
//关闭流
fis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
读文件分析
FileInputStream 对象的创建:FileInputStream fis = new FileInputStream("D:/a.txt");
关于FileInputStream对象的创建源码如下:(构造函数),它有三个重载的构造函数
public FileInputStream(String name) throws FileNotFoundException {
this(name != null ? new File(name) : null);
}
public FileInputStream(File file) throws FileNotFoundException {
String name = (file != null ? file.getPath() : null);
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkRead(name);
}
if (name == null) {
throw new NullPointerException();
}
if (file.isInvalid()) {
throw new FileNotFoundException("Invalid file path");
}
fd = new FileDescriptor();
fd.attach(this);
path = name;
open(name);
}
public FileInputStream(FileDescriptor fdObj) {
SecurityManager security = System.getSecurityManager();
if (fdObj == null) {
throw new NullPointerException();
}
if (security != null) {
security.checkRead(fdObj);
}
fd = fdObj;
path = null;
/*
* FileDescriptor is being shared by streams.
* Register this stream with FileDescriptor tracker.
*/
fd.attach(this);
}
读取文件的read方法源码:
它读取一个byte字节返回,如果已经读到了文件的未尾则返回-1
public int read() throws IOException {
return read0();
}
private native int read0() throws IOException;
如果需要一次读取多个节字则可以如下进行操作
byte
[] data =
new byte
[
100
];
int
read = fis.read(data); //
这个方法也有一个返回值int,它表示读取到的字节个数,如果读取时已经到了文件的未尾则返回-1
System.
out
.println(read);
System.
out
.println(
new
String(data,
0
,read));
这个方法的源码如下:
public int read(byte b[]) throws IOException {
return readBytes(b, 0, b.length);
}
private native int readBytes(byte b[], int off, int len) throws IOException;
还有一种方式进行读取【
这种方式常用】
byte
[] data1 =
new byte
[
100
];
int
read1 = fis.read(data1,
10
,
22
); //这里返回读取到了多少个字节,但是从字节数组下标为10的开始进行存储也就是前面的下标0-9中不存储读到的数据
System.
out
.println(read1);
System.
out
.println(
new
String(data1,
0
,read1));
这个方法的源码如下:
public int read(byte b[], int off, int len) throws IOException {
return readBytes(b, off, len);
}
private native int readBytes(byte b[], int off, int len) throws IOException;
如果我们的文件内容比较长,如何进行处理呢?
这个时候我们一般使用循环进行反复读取
如下代码
byte
[] data =
new byte
[
3
];
int
len =
0
;
while
((len = fis.read(data)) != -
1
){
System.
out
.print(
new
String(data,
0
,len));
}
注意:这里的byte字节的大小设置为3是考虑到可能中文乱码的问题,我们按一次3个字节的方式来读取可以暂时规避中文乱码问题,但是一般来说对于纯文本的文件来说读取一般考虑使用字符流的方式来进行读取(FileReader)。
使用FileReader进行文件的读取的步骤是不变的
1.创建一个FileReader
FileReader fr =
new
FileReader(
"D:/a.txt"
);
2.读取文件内容
读取年的方式也有三种
int read();
int read(char[] data);
int read(char[] data,int offset,int len);
读取的代码如下:
char
[] data =
new char
[
10
];
int
read = fr.read(data); //这个时候按字符来进行读取则不会存在中文乱码的问题
System.
out
.println(
new
String(data));
3.关闭IO流
fr.close();
写文件分析
写入文件的代码框架与读取的一致
//
创建一个
IO
流
FileOutputStream fos =
new
FileOutputStream(
"D:/c.txt"
);
//
写操作
fos.write(
"
你好,中国!
"
.getBytes());
//
关闭
IO
流
fos.close();
注意:在这里使用了FileOutputStream字节输出流,那么在调用write方时需要传入一个字节或者字节数组,上面方法调用时把要写入的字符串转为了一个字节数组
如果我们写入的是文本信息则可以选择字符流FileWriter来方便我们操作字符,相关代码如下:
FileWriter fw =
new
FileWriter(
"D:/c.txt"
);
fw.write(
"
你好,祖国!
"
);
fw.close();
注意:按上面的方式进行写入文本内容时会把原来D:\c.txt中的内容覆盖掉,这个时会把原来的内容全部清除掉然后把新的文本内容写入
如果我们需要使用追加的方式写入内容则可以如下
//
下面这种创建方式表示使用追加的方式
FileWriter fw =
new
FileWriter(
"D:/c.txt"
,
true
);
fw.write(
"
我是在后面再次写入的内容
"
);
fw.close();
也就是在创建输出流对象是地第二个参数指定为true,表示追加写入
文件复制操作
对于文件的复制操作有如下几个步骤
1.选择IO流
要读取源文件:FileInputStream (如果是文本类型的文件可以使用FileReader)
要输出到目标文件:FileOutputStream(如果是文本类型的文件可以使用FileWrite)
2.一边进行读取,同时进行写入
从源文件中读取数据后写入到目标文件中
3.关闭IO流
代码实现如下:
/**
* 复制一个文件
* @param srcPath 原文件的目录
* @param destPath 要复制到的文件目录
*/
public static void copyFile(String srcPath,String destPath) throws IOException {
// 创建IO流
FileInputStream fis = new FileInputStream(srcPath);
FileOutputStream fos = new FileOutputStream(destPath);
//进行数据的读、写操作
//定义一个缓冲字节数组,存储每次读取到的字节数据
byte[] data = new byte[1024]; //这里的1024表示一次最多读取1KB的字节数据,这里要做合理的设置,太大占用内存,太小则在大文件的复制过程中效率低下
int len;
while((len = fis.read(data))!=-1){
fos.write(data,0,len); //保证每次只写入读取到的字节数
}
//关闭IO流
fis.close();
fis.close();
}
缓冲IO流
缓冲IO流的目的是为了用来提高IO读写的效率,我们可以使用缓冲IO流来改造上述的文件复制过程
它的操作步骤如下:
1.选择IO流
从文件读,并且写到文件中的IO流:FileInputStream、FileOutPutStream
使用缓冲IO流来提高效率:BufferedInputStream(包装FileInputStream)、BufferedOutputStream(包装FileOutputStream)
2.一边读一边写
3.关闭IO流
代码实现如下:
/**
* 复制一个文件
* @param srcPath 原文件的目录
* @param destPath 要复制到的文件目录
*/
public static void copyFile(String srcPath,String destPath) throws IOException {
// 创建IO流
FileInputStream fis = new FileInputStream(srcPath);
FileOutputStream fos = new FileOutputStream(destPath);
// 对IO流进行包装,增加缓冲效果
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream bos = new BufferedOutputStream(fos);
//对文件进行读写操作
byte[] data = new byte[1024];
int len;
while((len = bis.read(data)) != -1){
bos.write(data,0,len);
}
//关闭IO流,这里需要注意,可以只关闭最外层的IO流,如要关闭全部则需要使用先创建后关闭的原则
bis.close();
fis.close();
bos.close();
fos.close();
}
IO流的异常处理
传统的异常处理的框架如下:
try{
//执行的代码块
} catch (Exception e){
//异常捕获后的处理
} finally{
//不管是否产生异常都会执行的语句
}
首先,我们在使用IO流的过程中可能会产生异常,需要使用try块进行包裹,并catch对应的异常
其次,我们在finally中关闭我们的IO流(原因是不管我们是否在使用IO流进行操作过程中是否产生了异常,都需要把创建的IO流关闭)
那么我们的copyFile方法,会如同如下:
/**
* 复制一个文件
* @param srcPath 原文件的目录
* @param destPath 要复制到的文件目录
*/
public static void copyFile(String srcPath,String destPath) {
// 创建IO流
FileInputStream fis = null;
FileOutputStream fos = null;
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
fis = new FileInputStream(srcPath);
fos = new FileOutputStream(destPath);
// 对IO流进行包装,增加缓冲效果
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
//对文件进行读写操作
byte[] data = new byte[1024];
int len;
while((len = bis.read(data)) != -1){
bos.write(data,0,len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
//关闭IO流,这里需要注意,可以只关闭最外层的IO流,如要关闭全部则需要使用先创建后关闭的原则
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
为什么在finally中也需要使用try呢?这个是由于我们关闭流的操作也是会有可能抛出异常的。
上面的写法看上去是非常繁琐的,在JDK1.7后新增语法如下:
try(资源声明){
...
} catch(Exception e) {
}
这个时候finally不用写了,使用完后,上的声明的资源会自动关闭
修改上面的复制文件的方法,代码如下:
/**
* 复制一个文件
* @param srcPath 原文件的目录
* @param destPath 要复制到的文件目录
*/
public static void copyFile1(String srcPath,String destPath) {
try(
//声明资源,在此处声明后会自动释放这些资源
FileInputStream fis = new FileInputStream(srcPath);
FileOutputStream fos = new FileOutputStream(destPath);
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream bos = new BufferedOutputStream(fos);
){
//对文件进行读写操作
byte[] data = new byte[1024];
int len;
while((len = bis.read(data)) != -1){
bos.write(data,0,len);
}
}catch (FileNotFoundException e){
e.printStackTrace();
} catch (IOException e){
e.printStackTrace();
}
}
上面的代码看上去则没有那么的繁琐,并且对于资源来说也一定会做到释放
注意:上面的代码需要在JDK 1.7之后的版本才能执行