javase输入输出流易被忽视的细节


关于流操作一些容易被忽视的细节:

1. 高级流在关闭的时候,只需要关闭其封装的低级流即可,高级流自动关闭。
2.InputStreamReader 和 OutputStreamReader 可以将输入输出字节流转化为字符流,因为字符流操作更为简便。
3.推回输入流,是PushbackInputStream 和 PushbackReader ,可以将内容返回缓冲区,读取数据时,优先从缓冲区查找。

可以用来查找某一连续字符串,普通流会涉及从中间割断目标字符串的可能。举例如下:

import java.io.*;


public class PushbackTest
{
	public static void main(String[] args) 
	{
		try(
			// 创建一个PushbackReader对象,指定推回缓冲区的长度为64
			PushbackReader pr = new PushbackReader(new FileReader(
				"PushbackTest.java") , 64))
		{
			char[] buf = new char[32];
			// 用以保存上次读取的字符串内容
			String lastContent = "";
			int hasRead = 0;
			// 循环读取文件内容
			while ((hasRead = pr.read(buf)) > 0)
			{
				// 将读取的内容转换成字符串
				String content = new String(buf , 0 , hasRead);
				int targetIndex = 0;
				// 将上次读取的字符串和本次读取的字符串拼起来,
				// 查看是否包含目标字符串, 如果包含目标字符串
				if ((targetIndex = (lastContent + content)
					.indexOf("new PushbackReader")) > 0)
				{
					// 将本次内容和上次内容一起推回缓冲区
					pr.unread((lastContent + content).toCharArray());
					// 指定读取前面len个字符
					int len = targetIndex > 32 ? 32 : targetIndex;
					// 再次读取指定长度的内容(就是目标字符串之前的内容)
					pr.read(buf , 0 , len);
					// 打印读取的内容
					System.out.print(new String(buf , 0 ,len));
					System.exit(0);
				}
				else
				{
					// 打印上次读取的内容
					System.out.print(lastContent);
					// 将本次内容设为上次读取的内容
					lastContent = content;
				}
			}
		}
		catch (IOException ioe)
		{
			ioe.printStackTrace();
		}
	}
}
4.java虚拟机读写其它进程的数据

import java.io.*;
import java.util.*;
/**
 * Description:
 * <br/>网站: <a href="http://www.crazyit.org">疯狂Java联盟</a> 
 * <br/>Copyright (C), 2001-2012, Yeeku.H.Lee
 * <br/>This program is protected by copyright laws.
 * <br/>Program Name:
 * <br/>Date:
 * @author Yeeku.H.Lee kongyeeku@163.com
 * @version 1.0
 */
public class WriteToProcess
{
	public static void main(String[] args)
		throws IOException
	{	
		// 运行java ReadStandard命令,返回运行该命令的子进程
		Process p = Runtime.getRuntime().exec("java ReadStandard");
		try(
			// 以p进程的输出流创建PrintStream对象
			// 这个输出流对本程序是输出流,对p进程则是输入流
			PrintStream ps = new PrintStream(p.getOutputStream()))
		{
			// 向ReadStandard程序写入内容,这些内容将被ReadStandard读取
			ps.println("普通字符串");
			ps.println(new WriteToProcess());
		}
	}
}
// 定义一个ReadStandard类,该类可以接受标准输入,
// 并将标准输入写入out.txt文件。
class ReadStandard
{
	public static void main(String[] args)
	{
		try(
			// 使用System.in创建Scanner对象,用于获取标准输入
			Scanner sc = new Scanner(System.in);
			PrintStream ps = new PrintStream(
			new FileOutputStream("out.txt")))
		{
			// 增加下面一行将只把回车作为分隔符
			sc.useDelimiter("\n");
			// 判断是否还有下一个输入项
			while(sc.hasNext())
			{
				// 输出输入项
				ps.println("键盘输入的内容是:" + sc.next());
			}
		}
		catch(IOException ioe)
		{
			ioe.printStackTrace();
		}
	}
}
5.java任意访问文件夹AccessRandomFile
向一个文件夹增加内容AccessRandomFile,基本原理就是先截取加入点之后的文本,放入临时文件,然后向原来的文本加字符串,最后把临时文本的内容导入到原文本。
import java.io.*;
class   RandomAccessTest
{
	public static void insertFile(String fileName,int pos,String insertContext) throws Exception
	{
		File temp=File.createTempFile("tem",null);
		temp.deleteOnExit();
		try(
		BufferedInputStream br=new BufferedInputStream(new FileInputStream(temp));
		BufferedOutputStream bw=new BufferedOutputStream(new FileOutputStream(temp));
		RandomAccessFile ra=new RandomAccessFile(fileName,"rw"))
		{
		ra.seek(pos);
		int leng=0;
		byte[] b=new byte[1024];
		while((leng=ra.read(b)) >0)
		{
			bw.write(b,0,leng);
		}
		bw.close();    //这一句话比较关键,否则无法把文本内容加进原文件中。但若是把BufferedInputStream 等换为 FileInputStream后,这句可以省略
			       //一个是缓冲流,需要把内容从缓冲区,刷新到文件中,另一个则不必这样做。
		ra.seek(pos);
		ra.write(insertContext.getBytes());
		while((leng=br.read(b)) >0)
		{
			ra.write(b,0,leng);
		}
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
	public static void main(String[]args) throws Exception
	{
		RandomAccessTest.insertFile("RandomAccessTest.java",10,"我是新来的,多多关照");
	}
}


6.序列化机制可以用来“克隆”对象
序列化和反序列化后,反序列化得到的对象和被序列化的对象值相同,得到的地址却不相同,且反序列化的过程与对象的构造器无关。

		Person p=new Person("孙行者",500);
		ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("temp.txt"));
		ObjectInputStream ois=new ObjectInputStream(new FileInputStream("temp.txt"));
		oos.writeObject(p);
		Person per=(Person)ois.readObject();
		System.out.println(p==per); // 打印false
除了 transient field (瞬态的)和 static field (属于类的)不可序列化之外,其它部分都可序列化。

建议给每一个将要被序列化的对象都加上field:private static final long serialVersionUID = -3273783136645942309L;  后面的值通过命令行

C:\Users\Administrator\Desktop\javaPractice>serialver Person  得到,若是不指定serialVersionUID 则不利于不同程序在不同的 JVM 之间移植。

注意:若是修改类中非静态field  非瞬态field,则可能导致序列化版本不兼容,则需要重新获取serialVersionUID 。

7. nio 效率高很多

将本文件输出到a.txt  并且打印出来

		File f =new File("FileChannelTest.java");
		try(FileChannel inFc =new FileInputStream(f).getChannel();
		FileChannel outFc =new FileOutputStream("a.txt").getChannel())
		{
		
		MappedByteBuffer buff =inFc.map(FileChannel.MapMode.READ_ONLY,0,f.length());
		outFc.write(buff);
		buff.flip();
		
		Charset cs=Charset.forName("GBK");
		CharBuffer cb =	cs.decode(buff);
		System.out.print(cb);

		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
将本文件复制一遍,这里得到的FileChannel可读可写,这取决于它的来源。
	File f=new File("FileChannelTest.java");
		try(RandomAccessFile raf =new RandomAccessFile("FileChannelTest.java","rw");
		FileChannel fc =raf.getChannel())
		{
			MappedByteBuffer bb =fc.map(FileChannel.MapMode.READ_ONLY,0,f.length());
			fc.position(f.length());
			fc.write(bb);
		}
		catch(Exception e)
		{ 
			e.printStackTrace();
		}
如果你处理很大的文件,你需要分次进行,有时候运气好会遇到很尴尬的问题,比方说:你的一次读取64个字节,正好第64个字节是半个汉字位,这就相当尴尬了。

报错:MalformedInputException: Input length = 1 ,如果允许的话,可以将源文件的那个部分稍微调整下,加个空格什么的,或者就是改变每次分割的大小,调整1个字节试试。

	File f =new File("FileChannelTest.java");
		try(FileChannel inFc =new FileInputStream(f).getChannel())
		{
		
		ByteBuffer buff = ByteBuffer.allocate(64);
		while(inFc.read(buff)!=-1)		
		{
		buff.flip();
		
		Charset cs=Charset.forName("GBK"); //我试试能乱码不
		CharsetDecoder deco=cs.newDecoder();
		CharBuffer cb =	deco.decode(buff);
		System.out.print(cb);
		
		buff.clear();
		}
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
8.文件锁
FileLock lock=fileChannel.tryLock();

fileChannel.lock();

9.NIO.2

点我查看更详细内容








  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值