这篇文章将介绍有关java IO输入输出流的知识。首先说说字符编码的问题,比较常用的编码有gbk,utf-8等。
1.gbk 编码中文占用2个字节,英文占用1个字节。
2、utf-8编码中文占用3个字节,英文占用1个字节。
Java是双字节编码,utf-16be编码。即char占用2个字节。注意:当你的字节序列是某种编码时,这个时候想把字节序列变成字符串,也需要用这种编码方式。否则会出现乱码。文本文件就是字节序列,可以是任意编码的字节序列。但是通常我们在中文的机器上直接创建文件,那么该文件只认识ANSI编码。
首先,介绍IO常用的第一个类File类(普通文件类)。
1、File类常用的API介绍
Java.IO.File类用于表示文件(目录),File类只用于表示文件(目录)的信息(大小,名称)等,不能用于文件内容的访问。常用的API如下:
boolean exists();判断文件是否存在
File file=new File(String path);创建File对象,这里path就是文件的绝对位置,如:c:\\file\\dooc 或者c:/file/dooc.txt都可以。
file.mkdir();创建目录
file.isDirectory();测试此抽象路径名表示的文件是否是一个目录。
file.isfile();测试此抽象路径名表示的文件是否是一个文件。
file.delete();删除这个文件或者目录
file.creatNewFile();创建新文件
file.getName();获取文件名或者目录的名称
file.getAbsolutepath();获取绝对路径
file.getParent();获取父级路径,如果没有则返回null
String[] list();返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中的文件和目录。
File[] listfiles();返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。
File类中的list()方法用于列出当前的目录下的子目录和文件,返回的是字符串数组。直接列出子目录的文件,但不包含子目录的文件内容。
代码如下:
//实现一个遍历File对象的指定文件目录下的所有文件
public static void listDirectory(File dir) throws IOException{
//判断dir目录存不存在
try {
if(dir.exists()){
System.out.println("该目录存在");
}else{
throw new IllegalArgumentException("这个目录不存在");
}
} catch (Exception e) {
// TODO: handle exception
System.out.println(e);
}
//判断目录下是否有文件
try {
if(dir.isDirectory()){
System.out.println("该目录存在文件夹");
}else{
throw new IllegalArgumentException("该目录不存在文件");
}
} catch (Exception e) {
// TODO: handle exception
System.out.println(e);
}
//方法一是调用list()方法来遍历,该方法返回的是一个字符串类型的数组
//我们依次遍历看看看结果
// String[] strs=dir.list();//返回的是路径名字符串数组
// //使用foreach语句来遍历
// for (String string : strs) {
// System.out.println(dir+"\\"+string);//加上根目录显示
// }
//
// System.out.println("上面的方法只能显示到子文件类型,既不能显示具体"
// + "的文件名称,也不能显示子文件下的文件");
System.out.println("");
//下面调用listFile()方法,该方法返回的是File对象的数组。同时可以直接获取file下的所有文件
File[] files=dir.listFiles();//返回的是文件对象数组
if(files!=null && files.length>0){//获取的数组即不为空,也不为0长度数组
for (File file : files) {//遍历每一个文件
if(file.isDirectory()){//查看是否还有文件在下面
listDirectory(file);//递归调用,直到没有子文件为止
}
else{
System.out.println(file);
}
}
}
}
总结:上面的测试类中包装了一些File的常用操作,例如过滤和遍历等:
1、列出指定目录下的(包含子目录)的所有文件。(这里是通过获取文件数组、遍历文件和递归调用实现的)
如果传进来的目录不存在或者不是文件夹,则应该抛出异常。这时我们需要用到判断语句。
2、file.list()方法;该方法返回当前目录下的文件名的字符串数组,但是不包含子目录下的文件和目录。
3、File[] files=file.listFile();可以直接获取file文件下的所有文件或者目录对象。然后以File对象数组的形式返回。然后可以调用递归就可以把所有的目录下的文件路径读出来,或者获取文件。
2、任意操作的文件类,RandomAccessFile类介绍。
RandomAccessFile类对文件进行访问读写文件。随机访问文件即指在文件的任意的位置上都可以。java文件模型在硬盘上的文件时,是以(字节)byte byte byte存储的,是数据的集合。
--打开文件
RandomAccessFile类,在打开文件时有2种模式可以打开文件:rw 读写模式和r只读模式。
如:RandomAccessFile raf=new RandomAccessFile(file,”rw”);
这里file的初始化如下:File file=new File(String path);
其中在读写文件时会有文件指针的存在,打开文件时文件的指针在开头,即pointer=0;
--写方法
raf.write(int);当写一个int型数据时只写一个字节(即最后8位,注意这里是一个字节一个字节的写。所以一个int型数据要分4次写进),同时文件指针pointer指向下一个位置准备再次写入。
--读方法
raf.seek(0);//将文件指针指向最开始的头部
byte[] buf=new byte[(int)raf.length()];//读取指定长度的字节内容
raf.read(buf);//读取指定长度的字节内容,并将内容存储在buf数组中
//读取一个字节
raf.seek(0);//将文件指针指向最开始的头部
int b=raf.read();//只读取一个字节
文件读写完毕后,一定要记得关闭文件
raf.close();
代码如下:
package com.ll.iofile;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;
/**
* 此方法用来测试RandomAccessFile类,用于读写文件
* @author LULEI
*
*/
public class testRandomAccessFile {
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
File file=new File("Demo");//判断相对路径中是否存在指定的目录
if(!file.exists()){
file.mkdir();//新建一个Demo目录
}
File file2=new File(file,"wq.bat");//将指定的文件实例化给file2对象
if(!file2.exists()){
file2.createNewFile();//新建一个wq.bat文件
}
//创建一个从中读取和向里面写入的一个随机访问的文件流.该文件要有指定的名称
RandomAccessFile raf=new RandomAccessFile(file2,"rw");//设置为读写模式
//首先观察一下文件指针的位置
System.out.println("文件指针的初始化位置在:"+raf.getFilePointer());
//向文件流中进行写,注意一次只写一个字节
raf.write('A');//注意char型字符占两个字节
System.out.println("文件指针的位置在:"+raf.getFilePointer());
String s="中";
byte[] sTObyte=s.getBytes("gbk");//设置为国标
raf.write(sTObyte);
System.out.println("添加中文后的文件指针的位置:"+raf.getFilePointer());
int iNum=89;//Int型数据要分4次写入到文件中,一次一个byte
raf.write(iNum>>>24);
raf.write(iNum>>>16);
raf.write(iNum>>>8);
raf.write(iNum>>>0);
System.out.println("普通方法添加int型数据后的文件指针的位置:"+raf.getFilePointer());
byte[] bt={1,2,3,4};
//可以写数组
raf.write(bt);
System.out.println("添加byte数组后的文件指针的位置:"+raf.getFilePointer());
//可以直接写一个Int类型的数据
raf.writeInt(20);//int占4个字节
System.out.println("添加int型数据后的文件指针的位置:"+raf.getFilePointer());
/*
* 向文件流进行读操作
*/
//一次只读一个字节的内容
raf.seek(0);//读取数据之前一定要将文件指针指向头部
int num=raf.read();
System.out.println("只读一个字节返回的内容:"+Integer.toString(num));
int num2=raf.read();
System.out.println("只读一个字节返回的内容(十六进制显示):"+Integer.toHexString(num2&0xff));
/*读取一定长度的字节的内容
* 读取文件前,一定要把文件指针指向开头
*/
raf.seek(0);
int n=(int)raf.length();//获取文件流中内容的字节长度
//创建一个同样长度大小的byte数组
byte[] buf=new byte[n];
raf.read(buf);//读取指定长度的字节内容,并将内容复制到buf数组中
System.out.println("读取一定长度返回的内容");
System.out.println(Arrays.toString(buf));
for (byte b : buf) {
System.out.print(Integer.toHexString(b & 0xff)+" ");
}
/*
* 最后关掉文件
*/
raf.close();
}
}
这篇就先介绍到这里。其实我在写这句代码时(如下):
RandomAccessFile raf=new RandomAccessFile(file,”rw”);
不知道有没有想到设计模式。是的,这里实际上就是一个装饰器模式。RandomAccessFile类是装饰器类,而File类是被装饰器类。通过包装,我们将原来的File类扩展为RandomAccessFile类。所以功能也就大大的提高了,其实在Java的整个IO框架中都大量的使用了装饰器模式。
这一篇就介绍到这里,下一篇将介绍Java 中IO的字节流。