Java I/O流——超详细,看这一篇就够了~~~

输入流

 程序在运行期间,可能需要从外部存储媒介或者其他程序中读入数据。这就需要输入流
 程序通过输入流读取和输入流相关的(输入流的指向称之为源)里面的数据。
Java I/O流——超详细,看这一篇就够了~~~_第1张图片

输出流

 程序在运行期间,可能需要将产生的数据存入到程序之外的地方,这个时候就要是要输出流
 程序通过输出流把程序中产生的数据送入目的地。
Java I/O流——超详细,看这一篇就够了~~~_第2张图片

File类

1、File类的构造函数
 File类对象主要用于获取文件自身的一些信息(文件所在目录、文件大小等等),但是不能用于操作文件内容。
 下面看看File类的构造方法:

		File(String filename);	//filename是文件的名,如果直接输入名字(比如1.txt)的话,那么就默认是相对路径
		
		File(String directoryPath , String filename);//directoryPath是文件路径
		
		File(File dir , String filename);//dir是目录,也就是一个文件夹

我们一般就用第一种就可以了。

2、文件的属性
 下面列举File类常用的方法:

File类对象 常用方法
public String getName() 获取文件名字
public boolean canWrite() 文件是否可写
public boolean canRead() 文件是否可读
public boolean exists() 判断文件是否存在
public long length() 获取文件长度(单位是字节)
public String getAbsolutePath() 获取文件的绝对路径
public String getParent() 获取文件的父目录
public boolean isFile() 判断文件是一个普通文件而不是文件夹
public boolean isDirectory() 判断文件是文件夹而不是一个普通文件
public long lastModified() 获取文件最后一次被修改的时间
public void CreateNewFile() 创建一个新的文件
public boolean delete() 删除指定文件

下面就给一个简单的例子:

package cn.com;

import java.io.File;
import java.io.IOException;

public class Test 
{
	public static void main(String args[])
	{
		File file = new File("E:\\java\\GUI\\src\\cn\\com\\Test.java");
		
		System.out.println(file.getName() + "是否存在:" + file.exists());
		System.out.println(file.getName() + "是否可写:" + file.canWrite());
		
		
		System.out.println(file.getName() + "是否可读:" + file.canRead());
		System.out.println(file.getName() + "是否可写:" + file.canWrite());
		
		System.out.println(file.getName() + "的长度为:" + file.length());
		System.out.println(file.getName() + "的绝对路径:" + file.getAbsolutePath());
		
		File file1 = new File("new.txt");
		System.out.println("在当前目录下创建一个新的文件:" + file1.getName());
		
		if(file1.exists()==false)
		try
		{
			file.createNewFile();
			System.out.println("创建成功");
		}
		catch(IOException e)
		{
			e.printStackTrace();
		}
		
		
	
	}
}

读者可以自己运行下看看效果。

3、文件的目录
 创建目录:

public boolean mkdir() 创建成功的话返回true;失败则返回false。注意,如果File对象本身就是所创建的目录的话那么也会创建失败

 输出目录下的所有文件名:
File类对象是目录的情况下,调用下面的方法:

File 对象 方法作用
public String[] list() 以字符串的形式返回该目录下的所有文件和子目录(这个时候返回的就是对于的文件名了)
public File[] listFiles() 以File对象的形式返回该目录下的所有文件和子目录

有的时候需要输出指定目录下的指定类型的文件(.txt,.java等),这个时候需要调用下列函数:

File 对象 方法作用
public String[] list(FilenameFilter obj) 以字符串的形式返回该目录下指定类型的所有文件(这个时候返回的就是对于的文件名了)
public Fiel[] listFiles(FilenameFilter obj) 以File对象的形式返回该目录下指定类型的所有文件

但是上面两种方法的FilenameFilter 是一个接口,它里面有一个方法:

public boolean accept(File dir , String name);

当File类对象是一个目录dirFile的时候,dirFile调用list(FilenameFilter obj)方法时,实现了FilenameFilter 接口的类调用accept()方法,其中dir参数是当前的总目录,参数name就是该目录下的一个文件名。当list返回true的时候就会将名字为name的文件存到对应的数组中。

下面就来看看例子:

package cn.com;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;

public class Test 
{
	public static void main(String args[])
	{
		//获取当前文件夹下所有以.java作为扩展名的文件名
		
		File file = new File("E:\\java\\GUI\\src\\cn\\com");
		
		//调用list方法获取该文件夹下所有以.java作为扩展名的文件名
		String[] filenames = file.list(new FilenameFilter()
				{
			//重写接口中的方法
			public boolean accept(File dir , String name)
			{
				return name.endsWith(".java");
			}
			
				});
		System.out.println(file.getName() + "文件夹下的所有.java文件名为:");
		for (String str : filenames)
			System.out.println(str);
		
		
		
	
	}
}

4、运行可执行文件
 要执行一个本地可执行文件的时候,使用Runtime类就行。直接调用exec()方法就行。
下面看看例子:

package cn.com;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;

public class Test 
{
	public static void main(String args[])
	{
		try
		{
			Runtime run = Runtime.getRuntime();	//获取Runtime类对象
			
			//运行桌面的Nodepad++
			File file = new File("D:\\Notepad++\\notepad++.exe");
			run.exec(file.getAbsolutePath());		
			//运行桌面的有道词典
			run.exec("C:\\Users\\86183\\AppData\\Local\\youdao\\dict\\Application\\YoudaoDict.exe");
			
		}
		catch(Exception e)
		{
			System.out.println(e);
		}
		
		
		
	
	}
}

文件字节输入输出流

1、输出:
 对文件写入的操作比较简单,直接使用FileOutputStream类就行(以字节为单位写)。它是OutputStream类的子类。
构造方法:

FileOutputStream(String name)
FileOutputStream(File file)
其中参数name 和 file指定的文件就是一开始提到的目的地。
注意:如果目的地文件不存在,系统会自动创建一个相应的文件;要是文件存在的话,就会从头开始写(也就是说会清空一开始的文件内容)。

不过要说一点:和C不同的是,Java提供了可以设置是否具有刷新功能的方法:

FileOutputStream(String name , boolean append)
FileOutputStream(File file , boolean append)
当参数append为true时,就不会刷新源文件的内容,也就是从文件的末尾开始写。

下面就开始写字节到指定的文件了:使用的是write()方法(顺序写入):

FileOutputStream对象 方法
void write(int n) 写入单个字节
void write(byte b[]) 写入一个字节数组
void write(byte b[] , int off , int len) 从字节数组b中的off位置开始写入len个字节
void close() 关闭输出流

在写的过程中,为了提高CPU的效率,程序通常先写到内存中(在内存中创建一个缓冲区),然后调用close()方法后系统就会将该内存中的数据洗到对应的磁盘里面。

下面看看具体的例子:

package cn.com;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.OutputStream;

public class Test 
{
	public static void main(String args[])
	{
		File file = new  File("C:\\Users\\86183\\Desktop\\1.txt");
		
		byte a[] = "Hello , world".getBytes();
		byte b[] = "Hello , world".getBytes();
		
		try 
		{
			//建立输出流,将他和要写入的文件绑定
			OutputStream out_file = new FileOutputStream(file , false);	
		
			//开始写数据进文件
			out_file.write(a);
			
			//写入完毕,关闭输出流
			out_file.close();
			/*
			//重新打开输出流————刷新的形式写
			out_file = new FileOutputStream(file , false);	
			out_file.write(b);
			out_file.close();*/
			

			//重新打开输出流————不刷新的形式写
			out_file = new FileOutputStream(file , true);	
			out_file.write('\n');
			out_file.write(b);
			out_file.close();

		
		
		} 
		catch (Exception e) 
		{
			e.printStackTrace();
		}
		
		System.out.println("文件操作完毕");
		
	
	}
}


2、输入:
 输入和输出形式基本差不多,只是用的函数不同。这里也简单介绍下:
对文件读取的操作比较简单,直接使用FileInputStream类就行(以字节为单位读)。它是InputStream类的子类。
构造方法:

FileInputStream(String name)
FileInputStream(File file)

下面就开始读取指定的文件了:使用的是read()方法(顺序读取):

FileInputStream对象 方法
int read() 读取单个字节,返回读取字节的字节值(0—255的整数);读取失败返回-1
int read(byte b[]) 读取byte.length个字节到b数组,如果没那么多的字节,就读取全部字节。返回实际读取到的字节数;到文件末尾返回-1
int read(byte b[] , int off , int len) 读取len个字节到b数组中;参数off指定b数组开始存放读取到的数据的起始位置
void close() 关闭输入流

下面看看例子:

package cn.com;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;


public class Test 
{
	public static void main(String args[])
	{
		File file = new  File("E:\\java\\GUI\\src\\cn\\com\\Test.java");
		
		byte a[]  = new byte[(int) file.length()];	
		
		try 
		{
			//建立输出流,将他和要写入的文件绑定
			InputStream read_file = new FileInputStream(file);	
		
			//开始写数据进文件
			read_file.read(a);
			
			//写入完毕,关闭输出流
			read_file.close();					
		
		} 
		catch (Exception e) 
		{
			e.printStackTrace();
		}
		
		System.out.println(new String(a , 0 , a.length));
		
	
	}
}

文件字符输入输出流

 上面提到的是字节输入输出流。以字节为单位的话不能很好的处理Unicode字符。如:一个汉字占连个字节,那你读取一个字节的话就会发生错误。
 字符输入输出流和字节输入输出流很类似,这里不再详细介绍了。
FileReader——文件字符输入流,父类是Reader
FileWriter——文件字符输出流,父类是Writer
下面看看构造方法:

FileReader(String filename)
FileReader(File file)
FileWriter(String filename)
FileWriter(File file)
FileWriter(String filename , boolean append)
FileWriter(File file , boolean append)

下面直接看看例子:

package cn.com;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;


public class Test 
{
	/*
	 * 从1.txt文件中读取数据写入2.txt文件中
	 */
	public static void main(String args[])
	{
		File file1 = new  File("C:\\Users\\86183\\Desktop\\1.txt");
		File file2 = new  File("C:\\Users\\86183\\Desktop\\2.txt");
		
		char a[] = new char[100];		//存储文件1中的数据
		
		try
		{
			//创建文件字符输入输出流
			Reader in_file = new FileReader(file1);
			Writer out_file = new FileWriter(file2 , false);
			
			in_file.read(a);
			out_file.write(a);
			
			in_file.close();
			//out_file.flush();
			out_file.close();
		
		} 
		catch (IOException e) 
		{
			e.printStackTrace();
		}
		System.out.println("文件操作完毕");
	
	}
}

注意上面有一句代码:

out_file.flush();
这里单独解释下:
对于Write流,write方法首先会将数据写入缓冲区,每当缓冲区满了之后里面的内容就会自动写入目的地,如果关闭流的话,缓冲区的内容就会被立即写入目的地。但是当调用flush()方法后,缓冲区里的内容就会被写入目的地。
Java I/O流——超详细,看这一篇就够了~~~_第3张图片

缓冲流

BufferedReaderBufferedWriter类创建的对象称之为缓存输入输出流。
BufferedReader的源是FileReader,BufferedWriter的目的地是FileWriter。
 他们的构造方法:

缓冲输入输出流 构造方法
BufferedReader BufferedReader(Reader in);
BufferedWriter BufferedWriter(Writer out);

BufferedReader 对象有一个方法readLine()可以按行读取文件。这是之前的文件字节和文件字符输出流所办不到的。
 同理,BufferedWriter对象使用write(String s , int off , int len);方法写入数据到目的地。
BufferedWriter对象还有一个newLine()方法向文件写入一个回车符。

这里来看一下缓冲输入输出流和文件字符输入输出流的关系:
Java I/O流——超详细,看这一篇就够了~~~_第4张图片

  • 注意:关闭流的时候,要先关闭上层输入流,在关闭底层输入流;在上层输入流调用flush()方法或者缓冲区满了之后,底层流会立即将缓冲区的数据写入目的地。上层流关闭后底层流会自动关闭。

下面看看具体的例子:

package cn.com;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.Reader;
import java.io.Writer;

public class Test 
{
	public static void main(String args[])
	{
		/*
		 * 借助缓冲输入输出流输出1.txt文件的内容并写入2.txt
		 */
		
		File file1 = new File("C:\\Users\\86183\\Desktop\\1.txt");
		File file2 = new File("C:\\Users\\86183\\Desktop\\2.txt");
		
		try
		{
			Reader read_file = new FileReader(file1); 		//创建文件字符输入流
			Writer write_file = new FileWriter(file2);		//创建文件字符输出流
			
			BufferedReader buff_read_file = new BufferedReader(read_file);//创建缓冲输入流
			BufferedWriter buff_writer_file = new BufferedWriter(write_file);//创建缓冲输出流
			
			//开始读取文件————按行读取
			char a[] = new char[(int)file1.length()];		//创建一个可以容纳文件1.txt全部内容的缓冲区
			String str = null;
			while((str = buff_read_file.readLine())!=null)
			{
				System.out.println(str);
				buff_writer_file.write(str); 				//向2.txt写入数据
				buff_writer_file.newLine();
				
			}
			buff_read_file.close();
			buff_writer_file.close();							
			
		}
		catch(Exception e)
		{
			System.out.println(e);
		}
		System.out.println("文件操作完成");
		
	}
}

随机流

 RandomAccessFile类对象创建的流既可以是输入流也可以是输出流,这个取决于它的构造函数的一个参数值。

随机流RandomAccessFile构造方法 参数说明
RandomAccessFile(String name , String mode) name是文件的名字,mode只能取值"r"——只读或者"rw"——可读可写
RandomAccessFile(File name , String mode) name是文件的名字,mode只能取值"r"——只读或者"rw"——可读可写

注意:随机流指向文件时,不会刷新文件,而且他还有对应的设置读写位置的方法seek(long a:参数a是距离文件开头的字节数。另外,还可以调用getFilePointer()方法获取文件当前读写位置

注意:当RandomAccessFile对象调用readLine()方法读取一行文本时,如果该行文本有非ASCII字符(如汉字)的话,必须将字符串用"iso-8859-1"重新编码存放到字节数组中,然后系统会自动转换输出。
看下面的例子:

package cn.com;


import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;


public class Test 
{
	public static void main(String args[])
	{	
		File file1 = new File("C:\\Users\\86183\\Desktop\\1.txt");
		
		try 
		{
			RandomAccessFile read_file = new RandomAccessFile(file1 , "r");
			String str = null;
			try 
			{
				while((str=read_file.readLine())!=null)
				{
					byte b[] = str.getBytes("iso-8859-1");
					System.out.println(new String(b));
				}
				read_file.close();
			} 
			catch (IOException e) 
			{
				e.printStackTrace();
			}
			
		} 
		catch (FileNotFoundException e) 
		{
			e.printStackTrace();
		}

		
	
		System.out.println("文件操作完成");
		
	}
}

RandomAccessFile 的方法太多,这里就不列举了。读者可以自己查阅。

数组流

 上面提到的源和目的地都是文件。其实源和目的地也可以是数组。
字节数组流

  • 字节数组输入流
字节数组输入流 构造方法
ByteArrayInputStream ByteArrayInputStream(byte[] buf) ,参数buf就是源
ByteArrayInputStream ByteArrayInputStream(byte[] buf , int offset , int length) ,参数buf是源,length参数指定读取的字节长度,参数offset指定从源的第几个字节开始读取
字节数组输入流 主要方法
ByteArrayInputStream read() 从源中读取一个字节
ByteArrayInputStream read(byte[] b , int off , int length) 从源中读取length个字节,将读取的字节放到b数组中,参数off设定b开始存储的位置
  • 字节数组输出流
字节数组输出流 构造方法
ByteArrayOutputStream ByteArrayOutputStream() ,默认指向32字节的缓冲区,当缓冲区写满时会自动增加
ByteArrayOutputStream ByteArrayOutputStream(int size) ,参数size指定缓冲区大小,当缓冲区写满时会自动增加

字符数组流
和上面对应的两个类是CharArrayReader和CharArrayWriter

下面直接看看具体例子吧:

package gen;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.CharArrayReader;
import java.io.CharArrayWriter;

public class Example_10 
{

	public static void main(String[] args) 
	{
		ByteArrayInputStream byte_array_input;		//字节数组输入流
		ByteArrayOutputStream byte_array_output;	//字节数组输出流
		
		CharArrayReader char_array_read;			//字符数组输入流
		CharArrayWriter char_array_write;			//字符数组输出流
		
		byte[] array_byte_content = "Hello , world,我是谁?".getBytes();				//源 字节数组
		char[] array_char_content = "I am come from China".toCharArray();			//源 字符数组
		
		try
		{
			byte_array_input = new ByteArrayInputStream(array_byte_content);//将 字节数组输入流 和 流 关联
			byte_array_output = new ByteArrayOutputStream();
			
			byte[] array = new byte[array_byte_content.length];
			byte_array_input.read(array);									//读取源中的数据到array
			byte_array_output.write(array);									//读取array中的数据到缓冲区
			
			System.out.println(new String(byte_array_output.toByteArray()));//输出缓冲区内容
			
		
			char_array_read = new CharArrayReader(array_char_content);		//将 字符数组输入流 和 流 关联
			char_array_write = new CharArrayWriter();
			

			char[] array1 = new char[array_char_content.length];
			char_array_read.read(array1);									//读取源中的数据到array
			char_array_write.write(array1);									//读取array中的数据到缓冲区
			System.out.println(new String(char_array_write.toCharArray()));	//输出缓冲区内容
			
			
		}
		catch(Exception e)
		{
			
		}
	

	}

}

数据流

DataOutputStreamDataInputStream类创建的对象是数据输出流数据输入流
 它允许程序按着和机器无关的风格读取Java原始数据,换句话说,读取这个数值的时候不需要去关心这个数值是多少字节。
下面看看构造函数

数据输出流 构造函数
DataOutputStream DataOutputStream (OutnputStream out),创建一个指向底层流out的数据输出流
数据输入流 构造函数
DataInputStream DataInputStream(InputStream in),创建一个指向底层流in的数据输入流

他们的具体实例方法这里就不一一列举了,下面直接看看具体代码吧:

package gen;


import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class Example_10 
{

	public static void main(String[] args) 
	{
		DataOutputStream data_output_stream;		//创建 数据输出流
		DataInputStream  data_input_stream;			//创建 数据输入流
		
		File file = new File("C:\\Users\\86183\\Desktop\\1.txt");
		try
		{
			if (file.exists())
				file.createNewFile();
			data_output_stream = new DataOutputStream(new FileOutputStream(file));
			//向文件输出数据
			data_output_stream.writeInt(100);
			data_output_stream.writeDouble(4.14);
			data_output_stream.writeBoolean(true);
			data_output_stream.writeChars("Hello , worlddd");
			data_output_stream.close(); 			//关闭数据输出流
			
			
			data_input_stream = new DataInputStream(new FileInputStream(file));
			System.out.println(data_input_stream.readInt());
			System.out.println(data_input_stream.readDouble());
			System.out.println(data_input_stream.readBoolean());
			
			char c='\0';
			while ((c =data_input_stream.readChar() )!='\0')
				System.out.print(c);
			
			data_input_stream.close(); 				//关闭输入流
			
		}
		catch(Exception e)
		{
			System.out.println(e.getMessage());
		}
		
		
		
	}

}

再来看一个关于字符串加密的例子:

package gen;

public class Encry_And_Dec 
{
		//解密算法
		public String Encrypt(String sourceString , String password)
		{
			char[] p = password.toCharArray();
			char[] s = sourceString.toCharArray();
			
			int p_length = p.length;
			int s_length = s.length;
			
			//开始加密
			for (int k = 0 ; k<s_length ; k++)
			{
				int mima = s[k] + p[k % p_length];
				s[k] = (char)mima;
			}
			return new String(s);
			
		}
		
		//解密算法
		public String Decrpty(String sourceString , String password)
		{
			char[] p = password.toCharArray();
			char[] s = sourceString.toCharArray();
			
			int p_length = p.length;
			int s_length = s.length;
			
			//开始解密
			for (int k = 0 ; k<s_length ; k++)
			{
				int mima = s[k] - p[k % p_length];
				s[k] = (char)mima;
			}
			return new String(s);
		}
		
		
	}



package gen;


import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class Example_10 
{

	public static void main(String[] args) 
	{	
		String str = "今天九点在城外集合";
		Encry_And_Dec person = new Encry_And_Dec();
		String password = "hahaha";					//加密的密码
		File file = new File("C:\\Users\\86183\\Desktop\\1.txt");
		
		//获取密文
		String serect = person.Encrypt(str, password);
		
		
		DataOutputStream data_output_stream;		//创建 数据输出流
		DataInputStream  data_input_stream;			//创建 数据输入流
		
		try
		{
			if (file.exists())
				file.createNewFile();
			data_output_stream = new DataOutputStream(new FileOutputStream(file));
			data_output_stream.writeUTF(serect);
			System.out.println("密文为:" + serect);
			
			data_input_stream = new DataInputStream(new FileInputStream(file));
			//读取密文
			System.out.println("原文为:" + person.Decrpty(data_input_stream.readUTF(), password));
		}
		catch(Exception e)
		{
			System.out.println(e.getMessage());
		}
	
		
	}
	
	

}

效果如下:
Java I/O流——超详细,看这一篇就够了~~~_第5张图片

对象流

ObjectOutputStreamObjectInputStream类创建的对象分别是对象输出流和对象输入流。
看看构造方法:

对象输出流 构造函数
ObjectOutputStream ObjectOutputStream(OutputStream in)
对象输入流 构造函数
ObjectInputStream ObjectInputStream(InputStream in)

他们分别调用writeObject和readObject方法写入和读取对象。
这里强调一点:使用对象流读写对象的时候,要保证对象是序列化的。只需要在编写类的时候实现Serializable接口就行。该接口的方法对外不可见,我们不需要去实现里面的具体方法。
下面就看看例子吧:

package gen;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Test 
{
	
	public static void main(String args[])
	{
		TV changhong = new TV();
		changhong.setName("长虹电视");
		changhong.setPrice(5600);
		
		try
		{
			//创建 对象输出流
			ObjectOutputStream objectOut = new ObjectOutputStream(new FileOutputStream("C:\\Users\\86183\\Desktop\\mytv.txt"));
			objectOut.writeObject(changhong); 			//将changhong对象写入文件
			objectOut.close();
	
			//创建对象输入流
			ObjectInputStream objectIn = new ObjectInputStream(new FileInputStream("mytv.txt"));
			TV xinfei = (TV)objectIn.readObject();		//从文件读取一个对象到内存
			xinfei.setPrice(6000);
			System.out.println("changhong的名字:" + changhong.getName() +",changhong的价格:" + changhong.getPrice() );
			System.out.println("xinfei的名字:" + xinfei.getName() +",xinfei的价格:" + xinfei.getPrice() );
			
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		
	}
	

}
class TV implements Serializable
{
	private String name;
	private double price;
	
	public void setName(String name)
	{
		this.name = name;
	}
	
	public void setPrice(double price)
	{
		this.price = price;
	}
	
	public String getName()
	{
		return this.name;
	}
	
	public double getPrice()
	{
		return this.price;
	}
	
	
}

序列化和对象克隆

看下面的例子:

A a = new A();
A b = a;

这个时候a和b指向同一个对象,如果修改a或者b中的任意一个,那么a和b都会改变,因为他们指向同一个对象。那么能不能得到a对象的一个复制品呢?当然是可以的,这里就要用到对象克隆了。
上面提到的对象流就是一个解决方法:将一个对象写入文件,然后用对象输入流从文件中读取这个对象。这样就完成的对象的克隆。
但是文件操作的话会很慢,要想快速的得到一个对象的克隆,我们可以将对象写入内存而不是写入文件。这就需要我们前面提到的数组流。
将数组流作为对象流的底层流就可以完成。
下面看看例子吧:还是上面的例子,这里我们改为用内存过度:

package gen;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Test 
{
	
	public static void main(String args[])
	{
		TV changhong = new TV();
		changhong.setName("长虹电视");
		changhong.setPrice(5600);
		
		try
		{
			
			ByteArrayOutputStream byte_write = new ByteArrayOutputStream();		//字节数组输出流
			ObjectOutputStream objectOut = new ObjectOutputStream(byte_write);	//创建对象输出流——输出到内存
			objectOut.writeObject(changhong); 			//将changhong对象写入文件
			objectOut.close();
	
			//创建对象输入流
			ByteArrayInputStream byte_read = new ByteArrayInputStream(byte_write.toByteArray());		//字节数组输入流
			ObjectInputStream objectIn = new ObjectInputStream(byte_read);
			TV xinfei = (TV)objectIn.readObject();		//从文件读取一个对象到内存
			xinfei.setPrice(6000);
			System.out.println("changhong的名字:" + changhong.getName() +",changhong的价格:" + changhong.getPrice() );
			System.out.println("xinfei的名字:" + xinfei.getName() +",xinfei的价格:" + xinfei.getPrice() );
			
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		
	}
	

}
class TV implements Serializable
{
	private String name;
	private double price;
	
	public void setName(String name)
	{
		this.name = name;
	}
	
	public void setPrice(double price)
	{
		this.price = price;
	}
	
	public String getName()
	{
		return this.name;
	}
	
	public double getPrice()
	{
		return this.price;
	}
	
	
}

文件对话框

 文件对话框(文件选择器)是一个选择文件的界面。
JFileChooser类的对象可以创建文件对话框。
 然后该类的对象可以调用下面两个方法显示文件对话框:

  • showOpenDialog(Component a);——提供打开文件界面
  • showSaveDialog(Component a);——提供关闭文件界面
    其中参数不为空时,就在组件a的正前面居中显示。

用户单击文件对话框上的打开或者取消时,对应的返回值分别是:JFileChooser.APPROVE_OPTIONJFileChooser.CANCEL_OPTION

如果希望文件对话框可以只打开你要的文件的话,可以让文件对话框对象调用
**setFileFilter()**方法。比如说:

			JFileChooser fileChoose = new JFileChooser();		//创建文件对话框			
			FileNameExtensionFilter filter1 = new FileNameExtensionFilter("java文件" , "java");
			FileNameExtensionFilter filter2 = new FileNameExtensionFilter("文本文件" , "txt");
			fileChoose.setFileFilter(filter1);
			fileChoose.setFileFilter(filter2);
			

这样一来可以加快选择

下面就给出一个综合一点的例子:(点击即可)
使用文件对话框保存和读取文件
这里还给大家提供一个JFileChooser有关的应用:
Java小程序——文件选择器,超实用

有关JFileChooser的具体用法请参考:JFileChooser文件选择器类详解

文件锁

有的时候会出现几个程序处理一个文件,这个时候有可能会出现混乱。Java随后就引入了文件锁的概念。
我们在使用文件输入输出流的时候就可以配合使用文件锁。
文件被锁定之后就不不能被其他程序操作。
下面结合RandomAccessFile来看看具体使用。
下面看看具体使用步骤:

  1. 使用RandomAccessFile流建立指向文件的流对象,该对象的读写属性必须是rw。
  2. RandomAccessFile流对象调用getChannel方法获取FileChannel对象。
  3. FileChannel对象调用tryLoak方法获得FileLock对象,这一个过程也称之为对文件加锁。
  4. FileLock对象调用release()方法解锁。

下面给出实例:

package cn.com;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

public class WindowFileLock extends JFrame
{
	private JButton button;
	private JTextArea textshow;
	private RandomAccessFile random_file;
	private FileLock lock;
	private FileChannel chanel;
	private boolean ifChage = false;

	public static void main(String[] args)
	{
		WindowFileLock win = new WindowFileLock();

	}
	
	public WindowFileLock()
	{
		init();
	}

	public void init()
	{
		JPanel nor_pan = new JPanel();
		
		try
		{
			File file = new File("C:\\Users\\86183\\Desktop\\1.txt");
			this.random_file = new RandomAccessFile(file,"rw");
			this.chanel = this.random_file.getChannel();
			this.lock =this.chanel.tryLock();		//对文件加锁	
			
		
		} 
		catch (Exception e) 
		{
			e.printStackTrace();
		}
		
		//初始化按钮
		this.button = new JButton("读取一行");
		this.button.setFocusPainted(false);
		this.button.setPreferredSize(new Dimension(90 , 30));
		nor_pan.add(this.button);
		
		//初始化文本区
		this.textshow = new JTextArea();
		this.textshow.setFont(new Font("华文行楷" , Font.PLAIN , 20));
		JScrollPane cen_pan = new JScrollPane(this.textshow);
		
		
		this.button.addActionListener(new ActionListener()
				{
					public void actionPerformed(ActionEvent e)
					{
					
						do_button_actionPerfered(e);
					}
			
				});
		
		
		
		this.add(nor_pan , BorderLayout.NORTH);
		this.add(cen_pan);
		
	
		
		
		//设置窗体属性
		this.setTitle("文件锁应用");
		this.setExtendedState(JFrame.EXIT_ON_CLOSE);
		this.setSize(400, 500);
		this.setVisible(true);
	}
	
	private void do_button_actionPerfered(ActionEvent e)
	{
		/*
		 * 读取一行后就对文件加锁
		 */
		if (e.getSource() == this.button)
		{
			if (this.ifChage == true)
			{
				JOptionPane.showMessageDialog(this, "文件已经读取完毕,无法再读取",null ,JOptionPane.WARNING_MESSAGE);
				return;
			}
				
			try
			{
					this.lock.release(); 			//解锁
					String str = this.random_file.readLine();
					this.textshow.append(str + "\n");
					if (str != null)
						this.lock = this.chanel.tryLock();	//读取完毕后立马加锁
					else if (str == null)
					{
						this.textshow.append("文件读取完毕\n");
						this.random_file.close();
						
						this.ifChage = true;
						
					}
			}
			catch(Exception e1)
			{
				e1.printStackTrace();
			}
		}
		
		}
		
	}

结尾

花了一些时间,将Java的I/O流做了一个简单的整理,作为以后的复习资料。
这里也和大家分享下,共同学习。
如果这篇博客对你有帮助的话就请点赞吧~~~~

你可能感兴趣的:(Java I/O流——超详细,看这一篇就够了~~~)