JAVA IO 专题

首先看一下常用的几种编码方式

public class EncodeDemo
{
	public static void main(String[] agrs)throws IOException
	{
		String s="中国ABC";
		byte[] byte1=s.getBytes(); //默认采用项目的UTF-8编码
		byte[] byte2=s.getBytes("GBK");//显示指定编码方式为GBK
		byte[] byte3=s.getBytes("UTF-16be");
 		for(byte b:byte1)
		{
			/**
			 * 把字节转换成int以十六进制的方式显示
			 * 默认采用项目的编码,此处使用UTF-8,得到的结果为e4 b8 ad e5 9b bd 41 42 43 
			 *可见采用utf-8编码,中文占用三个字节,英文占用一个字节
			 */
			System.out.print(Integer.toHexString(b & 0xff)+" ");
		}
 		System.out.println();
 		for(byte b:byte2)
		{
			/**
			 * 把字节转换成int以十六进制的方式显示,高位三个字节补0
			 * 显示指定编码方式为GBK,,得到的结果为d6 d0 b9 fa 41 42 43
			 * 可见采用GBK编码,中文占用三个字节,英文占用一个字节
			 */
			System.out.print(Integer.toHexString(b & 0xff)+" ");
		}
 		System.out.println();
 		for(byte b:byte3)
		{
			/**
			 * java是双字节编码utf-16be
			 * 把字节转换成int以十六进制的方式显示,高位三个字节补0
			 * 显示指定编码方式为UTF-16be,得到的结果为4e 2d 56 fd 0 41 0 42 0 43
			 * 可见采用UTF-16be编码,中文占用两个字节,英文也占用两个字节
			 */
			System.out.print(Integer.toHexString(b & 0xff)+" ");
		}
 		System.out.println();
 		/*
 		 * 字节数组转换成字符串,必须与之前的转换采用相同的编码方式,不然会出现乱码
 		 */
 		String s1 = new String(byte1); 
 		System.out.println(s1); //中国ABC,采用默认的项目编码格式
 		String s2 = new String(byte2);
 		System.out.println(s2);//�й�  出现乱码,因为byte2用的是GBK编码,转换成字符串时用得默认的UTF-8
 		String s3 = new String(byte2,"GBK");
 		System.out.println(s3);//中国ABC ,显示指定GBK编码方式,便不会出现乱码
	}
	
}

通过这个例子可以看出,常用的编码方式有UTF-8,汉字编码站三个字节,英文字母编码占用1个字节; GBK编码,中文占用两个字节,英文字母占用一个字节;java 是双字节UTF-16be编码,这种编码方式中文和英文都占用两个字节,在字符串与字节进行转换时,默认采用项目指定的编码方式,还要注意双向转换时,编码方式要相同,不然会出现乱码。


File类的使用

java.io.File类用于表示文件或目录,它只用于表示文件或目录的信息(名称,大小等),不能用于文件内容的访问

public class FileDemo {
	public static void main(String[] args)
	{
		/*
		 * 了解几种常用的构造函数
		 */
		File file = new File("F:\\开心");//注意:路径要使用双斜杠或者反斜杠
		System.out.println(file);
		File file2 = new File("F:\\开心","开心1.txt");
		File file3 = new File(file2,"开心2.txt");
		if(!file.exists())
		{
			/*
			 * 如果目录不存在,则创建目录,mkdirs()可用于创建多级目录
			 * file.createNewFile()用于创建文件
			 */
			file.mkdir(); 
		}
		else
		{
			file.delete();
		}
		/*
		 * File类的几种常用API
		 */
		System.out.println(file.isFile());
		System.out.println(file.isDirectory());
		System.out.println(file); //打印文件的路径
		System.out.println(file.getAbsolutePath());//同样打印文件的完整路径
		System.out.println(file.getName());//打印文件或目录的名字
		System.out.println(file.getParent());//打印文件或目录的父目录
		System.out.println(file.getParentFile());
	}

}

以上介绍FIle类创建对象的几种方式以及常用API



包装对对文件或目录的几种常用操作,如过滤,遍历等

/<span style="font-family: Arial, Helvetica, sans-serif;">/包装File的一些常用操作,如过滤,遍历</span>
public class FileUtil
{
	/*
	 * 遍历目录下的所有文件和目录
	 */
	public static void listDirectory(File dir)throws IOException
	{
		if(!dir.exists())
		{
			throw new IllegalArgumentException("目录"+dir+"不存在");
		}
		if(!dir.isDirectory())
		{
			throw new IllegalArgumentException(dir+"不是目录");
		}
		/*
		String[] fileNames = dir.list(); //返回字符串数组,直接子的名称,不包含子目录下的内容
		for (String string : fileNames)
		{
			System.out.println(string);
		}*/
		File[] files = dir.listFiles();
		if(files!=null && files.length>0)
		{
			for (File file : files)
			{
				System.out.println(file);
				if(file.isDirectory()) //递归遍历
				{
					listDirectory(file);
				}
			}
		}
	} 
}

RandomAccessFile:提供了对文件内容的访问,既可以读文件,也可以写文件。它提供对文件的随机访问,可以访问文件的任意位置

1>文件模式

    java文件,在硬盘上是byte byte byte...存储的,是数据的集合

2>打开文件

     打开文件有两种模式 “rw” 读写操作  “r”  只读操作

     RandomAccessFile  raf = new  RandomAccessFile  (file , "wr"),RandomAccessFile的随机访问是依靠文件指针实现的,打开文      件的默认指针位置prointer=0,即在文件的开头。读写操作会伴随着指针位置的移动。

3>写方法 

    raf.write(int), ----->只写一个字节,同时指针只想下一个位置,准备再次进行写操作

4>读方法

    raf.read()---->只写一个字节

5>文件读写完成后一定要关闭,不然会发生意想不到的错误

public class RandomAccessFileDemo {

	public static void main(String[] args)throws IOException
	{
		File file = new File("demo");
		if(!file.exists())
		{
			file.createNewFile();
		}
		RandomAccessFile raf = new RandomAccessFile(file, "rw");
		System.out.println(raf.getFilePointer()); //获取文件指针的位置,0
		raf.write('A');//只写入一个字节
		System.out.println(raf.getFilePointer()); //1
		int i = 0x7fffffff;//最大的整数
		//用write方法,每次只能写一个字节,写一个int需要写4次
		raf.write(i>>24);
		raf.write(i>>16);
		raf.write(i>>8);
		raf.write(i);
		//也可以直接写一个int,时机底层也是进行四次写操作
		raf.writeInt(i);
		System.out.println(raf.getFilePointer());
		String s="中国";
		byte[] byte1 = s.getBytes("gbk");
		raf.write(byte1);
		System.out.println(raf.length()); //文件的长度 13
		
		//读文件必须把文件指针移到文件的开始,也可以移到指定的位置进行读取
		raf.seek(0);
		byte[] buf = new byte[(int) raf.length()];
		raf.read(buf) ;//批量读取
		System.out.println(Arrays.toString(buf));
		//以十六进制的方式输出
		for (byte b : buf)
		{
			System.out.print(Integer.toHexString(b&0xff)+" ");
		}
		raf.close();
	}
}

I O流(输入流,输出流)

字节流

1>

InputStream 抽象了应用程序读取数据的方式,读到程序中为输入

OutputStream  抽象了应用程序写出数据的方式

2>

EOF =End 读到-1就读到了文件的结尾

3>输入流基本方法

int b = in.read(); 读取一个字节填充到int低八位

in.read(byte[] buf)  ; 批量读取字节到字节数组中

in.read(byte[] buf , int start ,int size)

4>输出流基本方法

out.write(int b) // 写出int b 的低八位到流

out.write(byte[] b) ; 写出字节数组中的全部字节

out.write(byte[] b , int start ,int size) //从下表start开始,写出size个字节

5>具体实现类  

FileInputStream --->具体实现了在文件中读取数据

/*
 * 读取指定文件内容,以十六进制输出到控制台
 * 每读取10个字节换行,
 * 单字节读取,不适合大文件,效率很低
 */
public class IOUtil
{
	public static void printHex(String filename)throws IOException
	{
		FileInputStream fis = new FileInputStream(filename);
		int b;
		int i=1;
		while((b=fis.read())!=-1) //每次只读取一个字节
		{
			if(b<=0xf)
				System.out.print("0"); //如果只有第四位,则在前面补零
			System.out.print(Integer.toHexString(b)+" ");
			if(i++%10 == 0)
			{
				System.out.println();
			}
		}
		fis.close();
	}
	/*
	 * 批量读取,大区大文件时效率很高
	 * 常用的文件读取方式
	 */
	public static void printHexByByteArray(String filename)throws IOException
	{
		FileInputStream fis = new FileInputStream(filename);
		byte[] buffer = new byte[10*1024];
		/*
		 * 从fis中批量读取字节,放入到buf中,从第0个位置开始放,最多放buffer.length个字节
		 * 返回的是读取字节的个数
		 * 为了防止一次读不完一个文件,所以用到while循环,读到文件结尾为止
		 */
		int n;
		while((n=fis.read(buffer, 0, buffer.length))!=-1)
		{
			int k=1;
			for (int i=0;i<n;i++)
			{
				if(buffer[i]<=0xf)
					System.out.print("0");
				System.out.print(Integer.toHexString(buffer[i]&0xff)+" ");
				if(k++%10 == 0)
					System.out.println();
			}
		}
		System.out.println();
		fis.close();
	}
	/*
	 * 文件的copy
	 */
	public static void  copyFile(File srcFile,File destFile)throws IOException
	{
		if(!srcFile.exists())
			throw new IllegalArgumentException("原文件"+srcFile+"不存在");
		if(!srcFile.isFile())
			throw new IllegalArgumentException(srcFile+"不是文件");
		FileInputStream in = new FileInputStream(srcFile);
		FileOutputStream out = new FileOutputStream(destFile);
		byte[] buf = new byte[10*1024];
		int n;
		while((n=in.read(buf, 0, buf.length))!=-1)
		{
			out.write(buf, 0, n);
		}
	}


FileOutputStream --->继承了OutputStream,具体实现了向文件中写入byte数据的方法

public class FileOutputStreamDemo1 {
	public static void main(String[] args)throws IOException
	{
		//如果文件不存在,则创建该文件,如果该文件存在,则删除后再重新创建
		FileOutputStream fos = new FileOutputStream("demo.dat",true);
		/*
		 * 如果文件不存在,则创建该文件,如果文件存在,则以追加的方式向文件中写数据
		 * FileOutputStream fos = new FileOutputStream("demo.dat","true");
		 */
		fos.write('A');  //写一个字节
		String s = "中国";
		byte[] b = s.getBytes();
		fos.write(b); //写一个字节数组
		fos.close();
	}
	public static void  copyFile(File srcFile,File destFile)throws IOException
	{
		if(!srcFile.exists())
			throw new IllegalArgumentException("原文件"+srcFile+"不存在");
		if(!srcFile.isFile())
			throw new IllegalArgumentException(srcFile+"不是文件");
		FileInputStream in = new FileInputStream(srcFile);
		FileOutputStream out = new FileOutputStream(destFile);
		byte[] buf = new byte[10*1024];
		int n;
		while((n=in.read(buf, 0, buf.length))!=-1)
		{
			out.write(buf, 0, n);
		}
	}
}

DataInputStrean 和 DataOutputStrean  采用装饰模式,底层包装一个字节的读取操作

                out.writeInt(10);
		out.writeInt(-10);
		out.writeLong(10l);
		out.writeDouble(1.11);
		out.writeUTF("中国");
		out.writeChars("中国人");
DataInputStrean中有与之对应的read操作


带缓冲的字节流

BufferedInputStreamBufferedOutputStream,为IO提供了带缓冲区的操作,一般打开文件进行写入或读取操作时,都会加上缓冲,这种流模式,提高了IO的性能

public static void  copyFileBuffer(File srcFile,File destFile)throws IOException
	{
		if(!srcFile.exists())
			throw new IllegalArgumentException("原文件"+srcFile+"不存在");
		if(!srcFile.isFile())
			throw new IllegalArgumentException(srcFile+"不是文件");
		BufferedInputStream in = new BufferedInputStream(new FileInputStream(srcFile));
		BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(destFile));
		int n;
		while((n=in.read())!=-1)
		{
			out.write(n);
			out.flush();//必须写
		}
		in.close();
		out.close();
	}



还可以自己写一个copyFileByByte(),经过比较,在进行较大的文件的copy工作时,自己创建byte[] 数组批量读取时,速度最快,带缓冲区的方式次之,当然可以想到,单个字节拷贝方式最慢。


字符流

1>认识文本和文本文件

java文本(char) 是16位无符号整数,是字符的Unicode编码(双字节编码)

文件是byte byte byte 。。 的序列集合

文本文件是文本按照一定的编码方式序列化为byte的存储方式

2>字符流(Reader Writer)

字符流的底层仍然是基本的字节序列

字符流的基本实现  ---->操作文本文本文件

   InputStreamReader -->完成byte流 解析为 char流 ,按照编码解析 

   OutputStreamWrite -->完成char流到byte流的解析,同样按照编码解析

public class FIRandFOW 
{

	public static void main(String[] args)throws IOException
	{
		FileInputStream in = new FileInputStream("C:\\unintall.log");
		/*
		 * 可以指定编码方式,自动识别换行
		 */
		InputStreamReader reader = new InputStreamReader(in,"GBk");
		FileOutputStream out = new FileOutputStream("C:\\unintall1.log");
		OutputStreamWriter writer = new OutputStreamWriter(out,"GBk");
		int a;
		/* 单个字符读取
		while((a = reader.read())!=-1)
		{
			System.out.print((char)a);
		}*/
		//批量读取
		char[] buffer = new char[8*1024];
		while((a=reader.read(buffer,0,buffer.length))!=-1)
		{
			writer.write(buffer, 0, a);
			writer.flush();//要加上刷新,才能及时将字符数组中的内容输出到文件
			String s = new String(buffer,0,a);
			System.out.println(s);
		}
	}
}

FileReader 和 FileWriter


同 InputStreamReader  和 OutputStreamWriter读取字符和字符数组方式一样,只是创建对象的方式不同

DataInputStrean
FileReader read = new FileReader(file);
FileWriter write = new FileWriter(file);  构造函数的参数是File对象

注:这种字符流操作存在一些缺陷,我们看到在构造方法中没办法指定编码方式,所以,读取文件的编码必须和文件的编码相同,不然会出现乱码


字符流的过滤器

BufferedReader 和 BufferedWriter PrintWriter
优点是能以行为单位进行文件的读取

public class BufferReaderWriter
{
	public static void main(String[] args) throws IOException
	{
		BufferedReader reader = new BufferedReader(
				new InputStreamReader(new FileInputStream("C:\\unintall.log"),"GBK"));
	    //BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("C:\\unintall1.log")));
	    PrintWriter pwriter = new PrintWriter("C:\\unintall1.log");
	    String line;
	    /*
	    while((line = reader.readLine()) != null)
	    {
	    	writer.write(line);//不识别换行
	    	writer.newLine();//手动换行
	    	writer.flush();
	    	System.out.println(line);
	    }*/
	    /*
	     * 由于BufferedWriter创建对象比较复杂,并且不识别换行,所以用PrintWriter替代
	     */
	    while((line = reader.readLine()) != null)
	    {
	    	pwriter.println(line); //用该方法进行换行
	    	pwriter.flush();
	    	System.out.println(line);
	    }
	}

}

以上就是javaIO的基本类以及常用的操作,我们完全可以参照这篇文章对API中的其他IO类进行扩展学习



DataInputStrean

你可能感兴趣的:(JAVA IO 专题)