Java I/O的基本架构
Java 的 I/O 操作类在包 java.io 下,大概有将近 80 个类,但是这些类大概可以分成四组,分别是:
- 基于字节操作的 I/O 接口:InputStream 和 OutputStream
- 基于字符操作的 I/O 接口:Writer 和 Reader
- 基于磁盘操作的 I/O 接口:File
- 基于网络操作的 I/O 接口:Socket(不在IO包下)
文件操作
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
//File.separator 表示 ‘/’或‘\’,linux和windows的目录斜杠不一样
//./表示在当前根目录下,项目的根目录在
File file=new File("."+File.separator+"test.txt");
System.out.println(file);
String fileName=file.getName();//获取文件或目录的名字
System.out.println(fileName);
long length=file.length();//获取文件的大小
System.out.println(length);
System.out.println(file.canRead());//文件是否可读
System.out.println(file.canWrite());//文件是否可写
System.out.println(file.isHidden());//文件是否隐藏
Date date=new Date(file.lastModified());//文件的最后修改时间
SimpleDateFormat sdf=new SimpleDateFormat("yyy-MM-dd HH:mm:ss");
System.out.println("最后修改时间:"+sdf.format(date));
//判断文件是否存在
System.out.println(file.exists());
if(file.exists()) {
//删除文件
file.delete();
}
System.out.println(file.exists());
if(!file.exists()) {
//创建文件
file.createNewFile();//创建文件或目录的时候会有异常抛出
}
System.out.println(file.exists());
System.out.println(file.length());
//目录篇
File dir = new File("demo");
if(!dir.exists()) {
//创建目录
dir.mkdir();
System.out.println("demo目录创建完毕!");
}
//创建多级目录
File dirs=new File("a"+File.separator+"b"+File.separator);
if(!dirs.exists()) {
dirs.mkdirs();
System.out.println("多级目录创建完毕!");
}
//删除目录:目录为空时才能删除
File f= new File("a"+File.separator+"b"+File.separator+"t.txt");
f.createNewFile();
if(dirs.exists()) {
dirs.delete();
}
//获取当前目录下的所有子项
File dirChildren =new File(".");
File[] subs=dirChildren.listFiles();
System.out.println(subs.length);
for(File fe:subs) {
System.out.println(fe.getName());
if(fe.isFile()) {//是否为文件
System.out.println("文件:"+fe.getName());
}else if(fe.isDirectory()) {//是否为目录
System.out.println("目录:"+fe.getName());
}
}
}
目录在删除时需要判定是否是空目录,在这里利用递归方法进行多级目录的删除。
递归:方法自己调用自己叫做递归,但要注意不能调用太多,且有合理的结束判断,以免死循环。
public static void main(String[] args) {
// TODO Auto-generated method stub
File file=new File("a");
delete(file);
}
/**
* 递归方法
* @param file
*/
public static void delete(File file) {
if(file.isDirectory()) {
//找到他的所有子项并且删除
File[] files=file.listFiles();
for(File f:files) {
delete(f);//递归方法。
}
}
file.delete();
}
通过FileFilter接口,可以自定义过滤器。
public class GetFile {
public static void main(String[] args) {
File file=new File(".");//当前目录即src目录下
FileFilter fi=new MyFillter();
File[] files=file.listFiles(fi);
for(File f:files) {
System.out.println(f.getName());
}
}
}
class MyFillter implements FileFilter{
@Override
public boolean accept(File file) {
// TODO Auto-generated method stub
String name=file.getName();
return name.startsWith("a");
}
}
java.io.RandomAccessFile:该类是基于指针形式读写文件数据的,写入的时字节,存储的是二进制的低八位。
public static void main(String[] args) throws Exception {
//创建文件,第一个参数可文件可路径,r是只读,rw是读写
RandomAccessFile raf=new RandomAccessFile("ioStream.txt", "rw");
//输入字节,写入的是二进制低八位,因此256写入0,257写入1
raf.write(97);
System.out.println("输入完毕");
raf.close();//关闭
RandomAccessFile raf1=new RandomAccessFile("ioStream.txt", "rw");
//读取文件内容
int d=raf1.read();
System.out.println(d);
raf1.close();//关闭
//复制文件
RandomAccessFile src=new RandomAccessFile("ioStream.txt", "r");
RandomAccessFile desc=new RandomAccessFile("ioStream_copy.txt", "rw");
int i=-1;
//一个字节一个字节读取,若读完,则指针返回-1
while((i=src.read())!=-1){
desc.write(i);
}
src.close();//关闭
desc.close();//关闭
//批量读取数据的方法
RandomAccessFile file=new RandomAccessFile("Linux的目录结构.png", "r");
RandomAccessFile file_copy=new RandomAccessFile("Linux的目录结构_copy.png", "rw");
byte[] buf= new byte[1024*10];//一次性读取该长度的字节
int len=-1;
while((len=file.read(buf))!=-1) {
file_copy.write(buf,0,len);
}
file.close();
file_copy.close();
//RandomAccessFile提供了方便读写的基本类型数据的相关方法
RandomAccessFile raf2=new RandomAccessFile("raf.dat","rw");
// raf2.write(null);//写入的是二进制
// raf2.writeInt(0);//写入的时Int类型
int imax=Integer.MAX_VALUE;
//连续写出4个字节,将int对应的2进制全部写出
raf2.write(imax>>>24);
System.out.println(raf2.getFilePointer());//获取当前RandomAccessFile的指针位置
raf2.write(imax>>>16);
System.out.println(raf2.getFilePointer());
raf2.write(imax>>>8);
System.out.println(raf2.getFilePointer());
raf2.write(imax);
raf2.writeInt(imax);
raf2.writeDouble(123.123);
raf2.writeLong(123L);
raf2.seek(0);//将RandomAccessFile指针的位置移动到文件的第一个字节处
raf2.close();
//向文件写入文本数据
RandomAccessFile raf3=new RandomAccessFile("raf.txt","rw");
String str="我爱我自己";//UTF-8中3个字节表示一个字符,GBK则是2个字节
byte[] data=str.getBytes();
raf3.write(data);
//或者
byte[] data1=str.getBytes("UTF-8");
raf3.write(data1);
raf3.close();
//读取字符串
RandomAccessFile raf4=new RandomAccessFile("raf.txt","r");
byte[] data2=new byte[100];
int len4=raf4.read(data2);
String str4=new String(data2,0,len4,"UTF-8");
System.out.println("实际读取到"+len4+"字节:"+str4);
}
字节流与字符流操作:
public static void main(String[] args) throws IOException, ClassNotFoundException {
//文件流:用于读写文件的流,是一对低级流
//文件流写入文件
// FileOutputStream fos = new FileOutputStream("fos.txt");//默认是覆盖写,即直接抹去原来的文件
FileOutputStream fos = new FileOutputStream("fos.txt",true);//追加写,在原文基础上继续写
String str="我很爱我自己!";
fos.write(str.getBytes());
fos.close();
//文件流读取文件内容
FileInputStream fis = new FileInputStream("fos.txt");
byte[] buf=new byte[100];
int len=fis.read(buf);
String s=new String(buf,0,len);
System.out.println(s);
fis.close();
//用文件流复制文件
fis=new FileInputStream("Linux的目录结构.png");
fos=new FileOutputStream("Linux的目录结构_copy.png");
buf=new byte[1024*10];
len=-1;
while((len=fis.read(buf))!=-1) {
fos.write(buf, 0, len);
}
fos.close();
fis.close();
/* 注意RandomAccessFile与文件流对文件的读写操作是不同的。
* 1.RAF是基于指针进行读写的,所以可以随意访问读写的任何位置,但是流不行,流只能向后读写,不能回头。
* 2.RAF既可以读又可以写,但是流要根据输入流读,用输出流进行写。
* 3.RAF可以将文件任何位置的数据覆盖,但是流不行,流要么将所有数据覆盖,要么就在末尾追加。
*/
//缓冲流:高级流 ,使用它们可以提高读写的效率
FileInputStream fis1=new FileInputStream("Linux的目录结构.png");
BufferedInputStream bis=new BufferedInputStream(fis1);
FileOutputStream fos1=new FileOutputStream("Linux的目录结构_copy1.png");
BufferedOutputStream bos=new BufferedOutputStream(fos1);
int d=-1;
//缓冲流在写时,如果数组没有被写满,在缓冲流关闭之前并不会进行写的操作,此时可以手动调用flush方法,强制将缓存的数据写出。
while((d=bis.read())!=-1) {
bos.write(d);
}
// bos.flush();
bis.close();
bos.close();//关闭方法里有flush方法。
/* 使用缓冲输入流的read方法读取一个字节时,实际上缓冲流内部有一个字节数组,会一次性读取若干个字节填满数组,然后将
* 第一个字节返回,当再次调用read方法,数组会直接返回第二个字节,而不是在去读取了。知道字节数组的所有字节都读取完毕了,才会
* 再一次读取一组字节回来。所以缓冲流是通过提高每次读写的数据量来减少实际的读写次数,提高读写效率。
*/
//对象流:可以很方便的将给定的对象转换为一组字节后写出
Person p=new Person();
p.setName("Tom");p.setSex("man");p.setAge(18);
FileOutputStream objFos=new FileOutputStream("personObj.txt");
ObjectOutputStream oos=new ObjectOutputStream(objFos);
oos.writeObject(p);//序列化。异常java.io.NotSerializableException: fourthtest.Person,原因是没有实现序列化接口
oos.close();
FileInputStream objFis=new FileInputStream("personObj.txt");
ObjectInputStream ois=new ObjectInputStream(objFis);
Person per=(Person)ois.readObject();//反序列化,关键在于版本号private static final long serialVersionUID = 1L;
System.out.println(per.toString());
ois.close();
/* 对象在序列化后得到的字节序列往往比较大,有时我们在对一个对象进行序列化时可以忽略某些不必要的属性,从而对序列化后得到
* 的字节序列瘦身。 在属性数据类型前夹transient
*/
//字符流:是以字符(char)为单位读写数据的。一次处理一个unicode,字符流的底层仍然是基本的字节流。
FileOutputStream fos2=new FileOutputStream("osw.txt");
OutputStreamWriter osw=new OutputStreamWriter(fos2);
String str2="我爱我自己";
osw.write(str2);
osw.write(",我也爱我爸爸妈妈。");
osw.close();
FileInputStream fis2=new FileInputStream("osw.txt");
InputStreamReader isr=new InputStreamReader(fis2);
char[] data=new char[100];
int len2=-1;
while((len2=isr.read(data))!=-1) {
System.out.println(new String(data,0,len2));
}
isr.close();
//转换字符集
FileOutputStream fos3=new FileOutputStream("osw_copy.txt");
FileInputStream fis3=new FileInputStream("osw.txt");
OutputStreamWriter osw3=new OutputStreamWriter(fos3, "gbk");
InputStreamReader isr3=new InputStreamReader(fis3,"gbk");
char[] data3=new char[100];
int len3=-1;
while((len3=isr3.read(data3))!=-1) {
osw3.write(data3,0,len3);
}
osw3.close();
isr3.close();
//缓冲字符流:可以按行读取写出字符串,并具有自动行刷新的功能。
PrintWriter pw= new PrintWriter("pw.txt");
pw.println("一二三四五");//写入并换行,一个换行符算2个字节
pw.print("五四三二一");
pw.close();
FileOutputStream fos4=new FileOutputStream("pw1.txt");
OutputStreamWriter osw4=new OutputStreamWriter(fos4, "gbk");
PrintWriter pw4=new PrintWriter(osw4);//当pw构造方法传入的第一个参数为流,那么就可以传入第二个参数,是一个boolean参数。若该
//参数为true,则当前pw具有自动行刷新。即每当使用println时,写出一行内容就会自动flush
pw4.println("我是第一行");
pw4.close();
FileInputStream fis4=new FileInputStream("pw.txt");
InputStreamReader isr4=new InputStreamReader(fis4,"gbk");
BufferedReader br=new BufferedReader(isr4);
String line=null;
while((line=br.readLine())!=null) {
System.out.println(line);//按行读取字符串时,该方法连续读取若干字符串,知道换行符为止,然后将换行符之前的所有字符组成一个字符串返回。
}
br.close();
}
待更新......