在Java中,把这些不同类型的输入、输出抽象为流(Stream),而其中输入或输出的数据称为数据流(Data Stream),用统一的接口来表示,从而使程序设计简单明了。

首先我要声明下:所谓的输入输出都是相对内存而言的

还要讲几个基本概念:字节流和字符流,字节流8位,主要由InputStream和OutputStream来处理。字符流16位,主要由Reader和Writer来处理。

节点流和处理流,磁盘或网络等读写的数据的流为节点流,对节点流进行封装和处理的流叫处理流。

InputStream和Reader都是抽象类,我用他们对File的实现类做例子,eg(FileInputStream)

public class FileInputStreamTest
{
	public static void main(String[] args) throws IOException
	{
		//创建字节输入流
		FileInputStream fis = new FileInputStream("FileInputStreamTest.java");
		//创建一个长度为1024的“竹筒”
		byte[] bbuf = new byte[1024];
		//用于保存实际读取的字节数
		int hasRead = 0;
		//使用循环来重复“取水”过程
		while ((hasRead = fis.read(bbuf)) > 0 )
		{
			//取出“竹筒”中水滴(字节),将字节数组转换成字符串输入!
			System.out.print(new String(bbuf , 0 , hasRead ));
		}
		fis.close();
	}
}

eg(FileReader)

public class FileWriterTest
{
	public static void main(String[] args) throws IOException
	{
		FileWriter fw = null;
		try
		{
			//创建字符输出流
			fw = new FileWriter("poem.txt");
			fw.write("锦瑟 - 李商隐/r/n"); 
			fw.write("锦瑟无端五十弦,一弦一柱思华年。/r/n");
			fw.write("庄生晓梦迷蝴蝶,望帝春心托杜鹃。/r/n");
			fw.write("沧海月明珠有泪,蓝田日暖玉生烟。/r/n");
			fw.write("此情可待成追忆,只是当时已惘然。/r/n");
		}
		catch (IOException ioe)
		{
			ioe.printStackTrace();
		}
		finally
		{
			//使用finally块来关闭文件输出流
			if (fw != null)
			{
				fw.close();
			}
		}
	}
}

以上是输入,下面讲下输出

OutputStream和Writer也是抽象类,我用他们对File的实现类做例子,eg(OutputStream)

public class FileOutputStreamTest
{
	public static void main(String[] args) throws IOException
	{
		FileInputStream fis = null;
		FileOutputStream fos = null;
		try
		{
			//创建字节输入流
			fis = new FileInputStream("FileOutputStreamTest.java");
			//创建字节输入流
			fos = new FileOutputStream("newFile.txt");
			byte[] bbuf = new byte[32];
			int hasRead = 0;
			//循环从输入流中取出数据
			while ((hasRead = fis.read(bbuf)) > 0 )
			{
				//每读取一次,即写入文件输出流,读了多少,就写多少。
				fos.write(bbuf , 0 , hasRead);
			}
		}
		catch (IOException ioe)
		{
			ioe.printStackTrace();
		}
		finally
		{
			//使用finally块来关闭文件输入流
			if (fis != null)
			{
				fis.close();
			}
			//使用finally块来关闭文件输出流
			if (fos != null)
			{
				fos.close();
			}
		}
	}
}

eg(Writer)

public class FileWriterTest
{
	public static void main(String[] args) throws IOException
	{
		FileWriter fw = null;
		try
		{
			//创建字符输出流
			fw = new FileWriter("poem.txt");
			fw.write("锦瑟 - 李商隐/r/n"); 
			fw.write("锦瑟无端五十弦,一弦一柱思华年。/r/n");
			fw.write("庄生晓梦迷蝴蝶,望帝春心托杜鹃。/r/n");
			fw.write("沧海月明珠有泪,蓝田日暖玉生烟。/r/n");
			fw.write("此情可待成追忆,只是当时已惘然。/r/n");
		}
		catch (IOException ioe)
		{
			ioe.printStackTrace();
		}
		finally
		{
			//使用finally块来关闭文件输出流
			if (fw != null)
			{
				fw.close();
			}
		}
	}
}

以上都是节点流的处理,但用起来比较麻烦,下面使用处理流来简化i/o操作

public class PrintStreamTest
{
	public static void main(String[] args)throws IOException
	{
		PrintStream ps = null;
		try
		{
			//创建一个节点输出流:FileOutputStream
			FileOutputStream fos = new FileOutputStream("test.txt");
			//以PrintStream来包装FileOutputStream输出流
			ps = new PrintStream(fos);
			//使用PrintStream执行输出
			ps.println("普通字符串");
			ps.println(new PrintStreamTest());
		}
		catch (IOException ioe)
		{
			ioe.printStackTrace(ps);
		}
		finally
		{
			ps.close();
		}
	}
}

转换流,主要用于从字节流到字符流,方便流的操作,然后利用BufferedReader来方便字符流的操作,eg

public class KeyinTest
{
	public static void main(String[] args) 
	{
		BufferedReader br = null;
		try
		{
			//将Sytem.in对象转换成Reader对象
			InputStreamReader reader = new InputStreamReader(System.in);
			//将普通Reader包装成BufferedReader
			br = new BufferedReader(reader);
			String buffer = null;
			//采用循环方式来一行一行的读取
			while ((buffer = br.readLine()) != null)
			{
				//如果读取的字符串为"exit",程序退出
				if (buffer.equals("exit"))
				{
					System.exit(1);
				}
				//打印读取的内容
				System.out.println("输入内容为:" + buffer);
			}
		}
		catch (IOException ioe)
		{
			ioe.printStackTrace();
		}
		//关闭输入流
		finally
		{
			try
			{
				br.close();				
			}
			catch (IOException ioe)
			{
				ioe.printStackTrace();
			}
		}
	}
}

最后讲下File类的使用,eg

public class FilenameFilterTest
{
	public static void main(String[] args) 
	{
		File file = new File(".");
		String[] nameList = file.list(new MyFilenameFilter());
		for (String name : nameList)
		{
			System.out.println(name);
		}
	}
}
//实现自己的FilenameFilter实现类
class MyFilenameFilter implements FilenameFilter
{
	public boolean accept(File dir, String name)
	{
		//如果文件名以.java结尾,或者文件对应一个路径,返回true
		return name.endsWith(".java")
			|| new File(name).isDirectory();
	}
}

注意我加了后缀的过滤,讲了File不得不补充RandomAccessFile,任意文件访问类,拥有reader和writer的功能,但要注意

他对文件的插入只是一种覆盖,eg

public class InsertContent
{
	public static void insert(String fileName , long pos , 
		String insertContent)throws IOException
	{
		RandomAccessFile raf = null;
		//创建一个临时文件来保存插入点后的数据
		File tmp = File.createTempFile("tmp" , null);
		FileOutputStream tmpOut = null;
		FileInputStream tmpIn = null;
		tmp.deleteOnExit();
		try
		{
			raf = new RandomAccessFile(fileName , "rw");
			tmpOut = new FileOutputStream(tmp);
			tmpIn = new FileInputStream(tmp);
			raf.seek(pos);
			//--------下面代码将插入点后的内容读入临时文件中保存---------
			byte[] bbuf = new byte[64];
			//用于保存实际读取的字节数
			int hasRead = 0;
			//使用循环方式读取插入点后的数据
			while ((hasRead = raf.read(bbuf)) > 0 )
			{
				//将读取的数据写入临时文件
				tmpOut.write(bbuf , 0 , hasRead);
			}
			//----------下面代码插入内容----------
			//把文件记录指针重新定位到pos位置
			raf.seek(pos);
			//追加需要插入的内容
			raf.write(insertContent.getBytes());
			//追加临时文件中的内容
			while ((hasRead = tmpIn.read(bbuf)) > 0 )
			{
				raf.write(bbuf , 0 , hasRead);
			}
		}
		finally
		{
			raf.close();
		}
	}
	public static void main(String[] args) throws IOException
	{
		insert("InsertContent.java" , 45 , "插入的内容/r/n");
	}
}