Java IO流
在Java编译中,IO系统主要负责文件的读写,一般在运行程序时,Java I/O程序将原磁盘、
文件或网络上的数据通过输入流类的相应方 法读入到内存,然后通过输出流类的相应方法
将处理完的数据写回目标文件、磁盘或网络资源指定的位置。
java.io.File 类:
1.File类的常用构造方法:
Public File(String pathName): 这个构造方法以pathName为路径创建File对象。
pathName可以是绝对路径,也可以是相对路径。
文件的绝对路径:完整的描述文件的位置的路径就是绝对路径。
文件的相对路径:从当前目录为参照点描述文件的位置的路径就是相对路径。
2.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(): 获取文件的路径。
· public String getAbsolutePath(): 获取文件的绝对路径。
· public String getCanonicalPath(): 获取文件的规范路径。
· public File getAbsoluteFile(): 得到绝对路径规范表示的文件象。
· public String getParent(): 得到文件的父目录路径名。
· public URI toURI(): 返回文件的统一资源标识符。
下面是访问创建文件的属性的例子:
<span style="font-family:Microsoft YaHei;font-size:14px;">import java.io.File;
import java.io.IOException;
public class TestFile {
public static void main(String[] args) throws IOException {
//使用指定的路径文件创建File对象
//文件必须存在,否则会抛出异常
File file = new File("H:/Users/Ashun/Desktop/文档
/source.txt");
System.out.println("文件或目录是否存在:" + file.exists());
System.out.println("是文件吗:" + file.isFile());
System.out.println("是目录吗:" + file.isDirectory());
System.out.println("文件是否可读: " + file.canRead());
System.out.println("文件是否可写: " + file.canWrite());
System.out.println("名称:" + file.getName());
System.out.println("路径:" + file.getPath());
System.out.println("绝对路径:" + file.getAbsolutePath());
System.out.println("绝对路径规范表示:" +
file.getCanonicalPath());
System.out.println("最后修改时间:" + file.lastModified());
System.out.println("文件的大小: " + file.length());
}
}</span>
输出结果:
文件或目录是否存在:true
是文件吗:true
是目录吗:false
文件是否可读: true
文件是否可写: true
名称:source.txt
路径:H:\Users\Ashun\Desktop\文档\source.txt
绝对路径:H:\Users\Ashun\Desktop\文档\source.txt
绝对路径规范表示:H:\Users\Ashun\Desktop\文档\source.txt
最后修改时间:1400920135348
文件的大小: 15
3.对文件的操作:
File类提供了如下操作方法:
· public boolean createNewFile(): 不存在时创建此文件对象所代表的空文件。
· public boolean delete(): 删除文件,目录必须是空的。
· public boolean mkdir(): 创建此抽象路径名指定的目录。
· public boolean mkdirs(): 创建此抽象路径名指定的目录, 包括所有必须但还不存在的父目录。
· public boolean renameTo(File dest): 重新命名此抽象路径名表示的文件 。
注:
mkdir和mkdirs的区别在于:如果file为最终文件,则两者都可用,如果file不为最终文件,
则只能用使用mkdirs来创建文件。
浏览目录中的文件和子目录方法:
· public String[] list(): 返回此目录中的文件名和目录名的数组。
· public File[] listFiles(): 返回此目录中的文件名和目录名的File实例数组。
· public File[] listFiles(FilenameFilter filter): 返回此目录中满足指定过滤器的文件和目录。
下面是操作一个文件或目录的例子:
<span style="font-family:Microsoft YaHei;font-size:14px;"> package File;
import java.io.File;
import java.io.IOException;
public class TestFile {
public static void main(String[] args) throws IOException {
File dir1 = new File("H:/Users/Ashun/Desktop/文/Test/dir1");
// 如果dir1不存在,就创建为目录
if (!dir1.exists()) {
dir1.mkdir();
}
// 以dir1为父目录创建名为dir2的File对象
File dir2 = new File(dir1, "dir2");
// 如果dir2不存在,就创建为目录
if (!dir2.exists()) {
dir2.mkdirs();
}
// 以dir3为父目录创建名为dir4的File对象
File dir4 = new File(dir1, "dir3/dir4");
// 如果dir4不存在,就创建为目录
if (!dir4.exists()) {
dir4.mkdirs();
}
// 创建以dir2为父目录,名为text.txt的File对象
File file = new File(dir2, "test.txt");
// 如果file不存在,就创建为目录
if (!file.exists()) {
file.createNewFile();
}
System.out.println("输出dir1的绝对路径名:");
System.out.println(dir1.getAbsolutePath());
System.out.println("输出dir2的绝对路径名:");
System.out.println(dir2.getAbsolutePath());
System.out.println("输出dir4的绝对路径名:");
System.out.println(dir4.getAbsolutePath());
System.out.println("输出test.txt的绝对路径名:");
System.out.println(file.getAbsolutePath());
//调用显示方法
listChilds(dir1, 0);
//调用删除方法
deleteAll(dir1);
}
//listChilds方法实现
private static void listChilds(File dir, int level) {
// 声成有层次感的空格
StringBuffer sb = new StringBuffer("|--");
for (int i = 0; i < level; i++) {
sb.insert(0, " ");
}
File[] childs = dir.listFiles();
// 递归出口
int length = childs == null ? 0 : childs.length;
for (int i = 0; i < length; i++) {
System.out.println(sb.toString() +
childs[i].getName());
if (childs[i].isDirectory()) {
listChilds(childs[i], level++);
}
}
if(length == 0)
return ;
}
//deleteAll方法实现
private static void deleteAll(File file) {
// 如果file代表文件,就删除该文件
if (file.isFile()) {
System.out.println("删除文件:" +
file.getAbsolutePath());
file.delete();
return;
}
// 如果file代表目录,先删除目录下的所有子目录和文件
File[] lists = file.listFiles();
for (int i = 0; i < lists.length; i++) {
// 递归删除当前目录下的所有子目录和文件
deleteAll(lists[i]);
}
//删除上一级的文件
System.out.println("删除目录: " + file.getAbsolutePath());
file.delete();
}
}</span>
输出结果:
输出dir1的绝对路径名:
H:\Users\Ashun\Desktop\文档\Test\dir1
输出dir2的绝对路径名:
H:\Users\Ashun\Desktop\文档\Test\dir1\dir2
输出dir4的绝对路径名:
H:\Users\Ashun\Desktop\文档\Test\dir1\dir3\dir4
输出test.txt的绝对路径名:
H:\Users\Ashun\Desktop\文档\Test\dir1\dir2\test.txt
|--dir2
|--test.txt
|--dir3
|--dir4
删除文件: H:\Users\Ashun\Desktop\文档\Test\dir1\dir2\test.txt
删除目录: H:\Users\Ashun\Desktop\文档\Test\dir1\dir2
删除目录: H:\Users\Ashun\Desktop\文档\Test\dir1\dir3\dir4
删除目录: H:\Users\Ashun\Desktop\文档\Test\dir1\dir3
删除目录: H:\Users\Ashun\Desktop\文档\Test\dir1
流类结构:
Java中流可以按如下方式分类:
1>按数据流分类:
· 输入流:程序可以从中读取数据的流。
· 输出流:程序能向其中输出数据的流。
2>按数据传输单位分:
· 字节流:以字节为单位传输数据的流。
· 字符流:以字符为单位传输数据的流。
3>按流的功能分:
· 节点流:用于直接操作数据源的流。
· 过滤流:也叫处理流,是对一个已经存在的流连接和封装,来提供更为强大、灵活的读写功能。
Java中的四种抽象流类:
字节流:
· 输入流:InputStream
· 输出流:OutputStream
字符流:
· 输入流:Reader
· 输出流:Write
1. InputStream和OutputStream:
1>InputStream抽象类是表示字节输入流的所有类的超类,以字节为单位从数据源中读取数据。
常用方法用:
· public abstract int read() throws IOException:
从输入流中读取数据的下一个字节,反会玩读到的字节,若遇到流的末尾,返回-1。
· public int read(byte[] b) throws IOException:
充数据流中读取b.length个字节的数据并存储到缓冲区数组b中,返回的是实际读到的字节数。
· public int read(byte[] b, int off, int len) throw IOException:
读取len个字节的数据,并从数据b的off位置开始写入到这个数组中。
· public void close() throws IOException:
关闭此输入流并释放与此流有关联的所有系统资源。
· public int vailable() throws IOException:
返回此输入留下一个方法调用可以不受阻塞地从此输入读取的估计字节数。
· public skip(long n) throw IOException:
跳过和丢弃此输入流中数据的n个字节,返回实现路过的字节数。
2>OutputStream抽象类是表示字节输入流的所有类的超类,以字节为单位从数据源中写出数据。
常用方法用:
· Public abstract void write(int b) throws IOException: 将指定的字节写入此输出流。
· public void write(byte[] b) throws IOException:将b.length个字节从指定的byte数组写入此输出流。
· public int write(byte[] b, int off, int len) throw IOException:
将指定byte数组中从从偏移量off开始的len个字节写入此输出流。
· public void flush() throws IOException:刷新此输出流,并强制写出所有缓冲的输去字节。
· public void close() throws IOException:关闭此输出流,并释放与此输出流有关的所有系统资源。
2. Reader和Writer:
Read和Write都是以字符为单位的抽象流类。
Read提供的方法:
· public int read() throws IOException : 读取单个字符,返回作为整数读取的字符,如果已经到达流的末尾返回-1.
· public abstract int read(char [] cbuf) throws IOException : 将字符串读入到数组,返回读取的字符数。
· public abstract int read(char[] cbuf, int off, int len)t hrows IOException :
读取len个字符的数据,并从数组cbuf的off位置开始存储。
· public abstract void close() throws IOEception: 关闭该流并释放所有与此相关的资源。
· Public long skip(long n) throws IOException: 跳过n个字符。
Write提供的方法:
· public int write(int c) throws IOException : 写入单个字符。
· public abstract int write(char [] cbuf) throws IOException : 写入字符数组。
· public abstract int write(char[] cbuf, int off, int len) throws IOException : 写入字符数组的某一部分。
· Public void write(String str) throws IOException: 写入字符串。
· public void write(String str, int off, int len) throws IOEception: 写入字符串的某一部分。
· public abstract void close() throws IOEception: 关闭该流,但要先刷新它。
· Public abstract void flush() throws IOException: 刷新该缓冲区,将缓冲区的数据全部写到目的地。
3.文件流:
文件流主要是指那些专门用于操作数据源中的文件的流,主要有FileInputStream、FileOutputStream、
FileReader、FileWriter四个类。
1>FileInputSteam和FileOutStream:
这两个类都是以字节为单位的文件输入和输出流,利用这两个类可以对文件进行读写操作。
下面是使用FileInputStream的例子:
<span style="font-family:Microsoft YaHei;font-size:14px;">import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class FileStream {
public static void main(String[] args) {
//创建一个连接到指定文件的FileInputStream对象
FileInputStream fin = null;
try {
fin = new FileInputStream("H:/Users/Ashun/Desktop/文档
/test.txt");
System.out.println("可读取的字节数:" + fin.available());
//读取数据,每次读取一个字节的数据,返回的是读到的字节
int i = fin.read();
while (i != -1) {//若遇到流的末尾,会返回-1
System.out.print((char) i);
i = fin.read();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
//如果数据读取完成关闭字节流
if (null != fin) {
fin.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}</span>
其中 H:/Users/Ashun/Desktop/文档/test.txt 中的内容为:
Hello World!
你好世界!
输出结果为:
可读取的字节数:25
Hello World??
??????????
上述程序中使用字节文件输入流从指定文件读取数据,并输出到控制台中。但会产生乱码,原因是:在Unicode编码中,
一个英文字符是一个字节编码的,而一个中文字符是用两个字节编码的,所以用字节流读取中文时肯定会出现问题。
下面是使用FileOutputStream类往类中写入数据的例子:
<span style="font-family:Microsoft YaHei;font-size:14px;"> package File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileStream {
public static void main(String[] args) {
// 创建一个连接到指定文件的FileOutputStream对象
FileOutputStream out = null;
try {
// 设置第二个参数为true,使用追加模式添加字节
out = new FileOutputStream("H:/Users/Ashun/Desktop/文档
/out.txt",true);
// 写入数据
out.write('#');
out.write("Hello World".getBytes());
out.write("你好世界".getBytes());
// 刷新输出流
out.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 如果数据读取完成关闭字节流
if (null != out) {
try {
out.close();
System.out.println("添加字节成功!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}</span>
其中文件 H:/Users/Ashun/Desktop/文档/out.txt 中的内容为:
#Hello World你好世界
注意:
在用字节流往文件中写入中文字符时是没有乱码的,因为程序先把中文字符转换成字节数组后再向文件中写入。
IO流对文件的操作步骤:
· 创建连接到指定数据源的IO流对象。
· 利用IO流类提供的方法进行数据的读写。
· 操作完后,一定要关闭该IO流对象。
2>FileReader和FileWriter:
用这两个流类操作以字符为单位的文件是在合适不过的了。
下面是实现复制字符文件的例子:
<span style="font-family:Microsoft YaHei;font-size:14px;">package File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class FileReaderOrWriter {
public static void main(String[] args) {
FileReader fr = null;
FileWriter fw = null;
int c = 0;
try {
// 创建IO流对象
fr = new FileReader("H:/Users/Ashun/Desktop/文档
/source.txt");
fw = new FileWriter("H:/Users/Ashun/Desktop/文档
/dest.txt");
// 往文件中写入字符数据
while ((c = fr.read()) != -1) {
fw.write(c);
}
// 刷新输出流
fw.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 如果数据读取完成关闭字节流
try {
if (null != fw) {
fw.close();
System.out.println("复制成功!");
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (null != fr) {
fr.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}</span>
运行之后产生一个dest.txt文件与source.txt文件相同。
3>缓冲流:
缓冲流可以明显的提高数据的读写速率,它在读取字节或字符时,会先把数据源读取到的数据添加到该内存缓冲区,
然后再返回;在写入字节或字符时,会先把要写入的数据填充到该内部缓冲区,然后一次性写入到目标数据源中。
缓冲流分为两类:
· BufferedInputStream 和 BufferedOutputStream:针对字节的缓冲输入流和输出流。
· BufferedReader 和 BufferedWriter:针对字符的缓冲流输入流和输出流。
缓冲流属于过滤流,不直接操作数据源,而是直接操作数据源的节点的一个包装流。
下面是用缓冲流来改写字符文件复制的功能:
<span style="font-family:Microsoft YaHei;font-size:14px;">package File;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class FileReaderOrWriter {
public static void main(String[] args) {
BufferedReader br = null;
BufferedWriter bw = null;
try {
// 创建IO流对象
br = new BufferedReader(new
FileReader("H:/Users/Ashun/Desktop/文档/source.txt"));
bw = new BufferedWriter(new
FileWriter("H:/Users/Ashun/Desktop/文档/dest.txt"));
String str = null;
//一次读取字符文本的一行字符
while ((str = br.readLine()) != null) {
//一次写入一行字符
bw.write(str);
//写入行分隔符
bw.newLine();
}
// 刷新输出流
bw.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 如果数据读取完成关闭字节流
try {
if (null != bw) {
bw.close();
System.out.println("复制成功!");
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (null != br) {
br.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}</span>
注意:
在使用过滤流的过程中,当关闭过滤流时,它会自动关闭它所包装的底层节点流。所以无须在手动关闭节点流了。
4>数据流:
数据流主要有两个类DataInputStream和DataOutputStream,分别用来读取和写出基本数据类型的数据。
DataInputStream类中提供方法:
· public final boolean readBoolean(): 从输入流中读取一个布尔型的值。
· public final byte readByte(): 从输入流中读取一个8位的字节。
· public final char readChare(): 读取一个16位的Unicode字符。
· public final float Float(): 读取一个32位的单精度浮点数。
· public final double readDouble(): 读取一64位的双精度浮点数。
· public final short readShort(): 读取一个16位的短整数。
· public final int readInt(): 读取一个32位的整数。
· public final long readLong(): 读取一个64位的长整数。
· public final void readFully(byte[] b): 从当前数据输入流中读取b.length个字节到该数组。
· public final void readFully(byte[] b, int off, int len):
从当前数据流中读取len个字节到该数组,数组开始位置为off。
· public int skipBytes(int n): 跳过n个字节。
· public final String readUTF(): 读取一个由UTF格式字符组成的字符串。
在DataOutputStream中有与之对应的read和write方法。
下面是使用数据流的例子:
<span style="font-family:Microsoft YaHei;font-size:14px;">import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileReaderOrWriter {
public static void main(String[] args) {
DataOutputStream dos = null;
try{
//创建连接到指定的文件的数据流对象
dos = new DataOutputStream(new
FileOutputStream("H:/Users/Ashun/Desktop/文档/data.txt"));
//写入UTL字符串
dos.writeUTF("ab中国");
//写入布尔型值
dos.writeBoolean(false);
//写入长整数
dos.writeLong(1234567890L);
System.out.println("写入数据成功!");
}catch(IOException e){
e.printStackTrace();
}finally{
try{
if(null != dos){
dos.close();
}
}catch(IOException e){
e.printStackTrace();
}
}
}
}</span>
运行之后会在 H:/Users/Ashun/Desktop/文档/data.txt 中生成一个
data.txt 文件,其内容为: ab涓浗 I??
这些代码需要借助DataInputStream来读出。