Java IO使用和总结

Java IO使用和总结

上篇文章提到了NIO的使用,这篇总结下IO的使用;不详谈语法,仅分析特点,从而明确它们的使用范围,这样就能够在合适的场合想到并应用它们。

1.IO的数据源和输出目标

IO的数据源和输出目标大致分为以下几类:

1)文件

2)管道

3)网络连接

4)内存缓存

5)系统输入输出

下面逐一分析

2.文件

	/**2.文件
	 * 你可以根据该文件是二进制文件还是文本文件来选择使用FileInputStream或者FileReader
	 * 如果你需要跳跃式地读取文件其中的某些部分,可以使用RandomAccessFile
	 * 注意:
	 * 有时候你可能需要读取文件的信息而不是文件的内容,举个例子,如果你需要知道文件的大小
	 * 和文件的属性。对于目录来说也是一样的,比如你需要获取某个目录下的文件列表。通过File
	 * 类可以获取文件和目录的信息。
	 */

3.管道

	/**3.管道(在上一篇NIO的总结中提到了它,并且举了一个示例)
	 * Java IO中的管道为运行在同一个JVM中的两个线程提供了通信的能力。
	 * 你不能利用管道与不同的JVM中的线程通信(不同的进程)。在概念上,Java的管道不同于Unix/Linux
	 * 系统中的管道。在Unix/Linux中,运行在不同地址空间的两个进程可以通过管道通信。在Java中,通
	 * 信的双方应该是运行在同一进程中的不同线程。
	 * 
	 * 除了管道之外,一个JVM中不同线程之间还有许多通信的方式。实际上,线程在大多数情况下会传递
	 * 完整的对象信息而非原始的字节数据。但是,如果你需要在线程之间传递字节数据,Java IO的管道
	 * 是一个不错的选择。
	 * 
	 * 管道的本质是一样的,只是在应用时,在IO和NIO中的语法不同而已
	 */

4.网络连接

	/**4.IO 网络
	 * Java网络API用来在不同进程之间建立网络连接,而Java IO则用来在建立了连接之后的进程之间交换数据
	 * 下面的一个写法,不使用FileInputStream而是InputStream,是因为可以这样的话还可以同时接收来自网络的输入,再
	 * 延伸一下,java.io.InputStream类是所有Java IO输入流的基类。如果你正在开发一个从流中读取数据的组件,请尝试
	 * 用InputStream替代任何它的子类(比如FileInputStream)进行开发。这么做能够让你的代码兼容任何类型而非某种确定
	 * 类型的输入流 ;同样的,OutputStream也是一样。如下面一个例子
	 */
/*下面的一个写法,不使用FileInputStream而是InputStream,是因为可以这样的话还可以同时接收来自网络的输入*/
	public class MyClass {
	    public static void main(String[] args) {
	        InputStream inputStream = new FileInputStream("c:\\myfile.txt");
	        process(inputStream);
	    }
	    public static void process(InputStream input) throws IOException {
	        //do something with the InputStream
	    }
	}

5.内存缓存

	/**5.IO 读取或者获得字节(字符数组)    可以把这个理解为内存缓存
	 * 5.1 用ByteArrayInputStream或者CharArrayReader封装字节或者字符数组,然后从数组中读取数据成为流,
	 * 以同样的方式也可以用于读取字符数组,只要把字符数组封装在CharArrayReader上就行了。
	 * byte[] bytes = new byte[1024];
	 * InputStream input = new ByteArrayInputStream(bytes);
	 * 
	 * 5.2 把数据写到ByteArrayOutputStream或者CharArrayWriter中,只要调用toByteArray()或者toCharArray,
	 * 所有写入的数据就会以数组的形式返回
	 * OutputStream output = new ByteArrayOutputStream();
	 * output.write("This text is converted to bytes".getBytes("UTF-8"));
	 * byte[] bytes = output.toByteArray();
	 */

有一个深复制的问题,就可以使用这个思想来做; 如果一个对象数组List<Object>, 如何得到它的一份拷贝,我们所熟悉的add()方法,adllAll()方法,还有system.copy等都不能实现,我们需要的是一个新的List,而且其中的每一个对象都是新的,可以把Object 序列化,然后将Ist.LIst<Object>拷贝到内存中,以ByteArray的形式存放,然后从内存种读取这个 ByteArray到一个新的List<Object>中(反序列化),下面是示例:

/*引出一个深复制的问题,代码如下:*/
	public static <T> List<T> deepCopy(List<T> src) throws IOException, ClassNotFoundException {  
	    ByteArrayOutputStream byteOut = new ByteArrayOutputStream();  
	    ObjectOutputStream out = new ObjectOutputStream(byteOut);  
	    out.writeObject(src);  
	  
	    ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());  
	    ObjectInputStream in = new ObjectInputStream(byteIn);  
	    @SuppressWarnings("unchecked")  
	    List<T> dest = (List<T>) in.readObject();  
	    return dest;  
	}

6.系统输入输出

/**6.替换系统流  系统输入输出
	 * System.in, System.out, System.err本身没什么可讲的。但是有一点;尽管System.in, System.out, 
	 * System.err这3个流是java.lang.System类中的静态成员(译者注:这3个变量均为final static常量),
	 * 并且已经预先在JVM启动的时候初始化完成,你依然可以更改它们。只需要把一个新的InputStream设
	 * 置给System.in或者一个新的OutputStream设置给System.out或者System.err,之后的数据都将会在新
	 * 的流中进行读取、写入。如下案例:
	 * 
	 * 注意:flush的调用,什么时候调用flush?
	 * 1)FileOutPutStream继承outputStream,并不提供flush()方法的重写,所以无论内容多少write都会
	 * 将二进制流直接传递给底层操作系统的I/O,flush无效果
	 * 而Buffered系列的输入输出流函数单从Buffered这个单词就可以看出他们是使用缓冲区的,应用程序
	 * 每次IO都要和设备进行通信,效率很低,因此缓冲区为了提高效率,当写入设备时,先写入缓冲区,
	 * 等到缓冲区有足够多的数据时,就整体写入设备,所以它需要使用flush方法手动强制写出;
	 * 2)close()方法中包含了flush()的操作,但是马上就关闭流,所以如果想强制刷新缓冲区,然后继续使用
	 * 流的话,就用flush
	 */
	OutputStream output = new FileOutputStream("c:\\data\\system.out.txt");
	PrintStream printOut = new PrintStream(output);
	System.setOut(printOut)

下面讲述一些IO中的其他相关需要学习其特点和注意的地方

7

	/**7.PushbackInputStream
	 * 可以获取输入流之后,处理,然后再反过来放入输入源中。
	 */

8

/**8 关于流的整合问题
	 * Stream可以与Reader或者Writer整合
	 * Reader或者Writer可以与Buffer整合
	 */

9

/**9.之前说到了不在service层try catch,而是在方法体上throws异常:http://blog.csdn.net/Jintao_Ma/article/details/52853865
 * 但是如果在service层关闭流的时候可能要用到try catch finally,这个时候,上层如何回复消息给用户?
 * 个人认为一个比较好的解决方法是:在service的方法体上加上返回值,然后将service内部的异常信息描
 * 述成用户能识别的内容,之后放入返回值中,在controller层捕获异常,
 * 1)有异常 2)没有异常,那么有两种情况
 * 2.1)service层的异常,2.2)确实没有异常 这三种情况都可以返回给用户
public static void main(String[] args) throws FileNotFoundException, IOException {
	try(FileInputStream fileInputStream = new FileInputStream(new File("test.txt"))){
		System.out.println("Channel2.main()");
	}
	}
	
	public BaseResult controllerMethod{ /*假设是controller层次*/
		BaseResult baseResult = new BaseResult();
		
		try {
			BaseResult = serviceMethod();
		} catch (Exception e) {
			BaseResult.setIsSuccess(false);
			BaseResult.serErrMsg("业务异常");
		}finally{
			return BaseResult;
		}
	}
	public BaseResult serviceMethod() throws Exception(){
		BaseResult baseResult = new BaseResult();
		
		try{
			InputStream input = new FileInputStream("c:\\data\\input-text.txt");
			doSomethingWithData(input);/*对输入流做一些处理*/
		}catch(IOException e){
			System.out.println(e.getMessage());
			baseResult.setIsSuccess(false);
			baseResult.serErrMsg("流异常");
			return baseResult;  /*这个return 在finally执行后再执行*/
		}finally{
			input.close();/*关闭流*/
		}
		
		doOthers();/*可能会有异常,在方法体上抛出*/
		baseResult.setIsSuccess(true);
		return baseResult;
	}

那么还有没有其他的方法呢,其实是有的,那就是在关闭流的时候不使用finally,这样的话就不用try catch,就可以在方法体上throws异常,从而不影响我们之前文章总结的理论; JDK7及以上就提供了这种方法,称作try with resources, 顾名思义就是在try参数中加上资源,如下:

	public static void main(String[] args) throws FileNotFoundException, IOException {
	try(FileInputStream fileInputStream = new FileInputStream(new File("test.txt"))){
		System.out.println("Channel2.main()");
	}
	}

另外再提到一点,关于异常处理,在C++中有异常模板,在Java中有异常框架,这一部分后面有时间再探究(这里备注下,提醒还有关于异常处理更标准的方法)

10

	/**10.关于RandomAccessFile的使用 可以在任意位置读取文件
	 * seek 指定一个指针
	 * getFilePointer 方法
	 */

11

 
	/**11.DataInputStream与DataOutputStream可以处理java基本类型的数据
	 */

12

	/**12.ObjectInputStream与ObjectOutputStream 处理java序列化的对象
	 */

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值