`

IO流及其一些操作

阅读更多

写在前面,本文章的目标是基本覆盖JavaIO的全部内容,然后,文章还是以例子为主,因为我觉得学以致用才是真,写出来的代码才是自己的代码,而不是看的。

 

学习Java的IO流,首先就是学习文件(也就是File类)。

 

文件类

 

下面我们来示例一下如何通过File类创建一个新文件。 

import java.io.*;
public class Hello{
    	public static void main(String[] args) {
        	File f=new File("D:\\hello.txt");
        	try{
            		f.createNewFile();
        	}catch (Exception e) {
            		e.printStackTrace();
        	}
   	 }
}

 

【运行结果】:

 

程序运行之后,在d盘下会有一个名字为hello.txt的文件。

通过创建File类的对象,可以获取到对象的许多操作:



 比如说删除一个文件:

f.delete();

 创建一个文件夹:

f.mkdir();

 等等……

 

然后我还了解到一个我认为是很必要的一个习惯:

就是改写

File f=new File("D:\\hello.txt");

 

中文件路径的写法;

首先我们要知道File类的两个常量:



 此处可能有些同学认为,我在Windows下直接使用"\"分割不就行了吗?这当然是可以的,但是到了Linux下就不是"\"了,所以为了我们代码的健壮性和跨平台性,推荐使用这些常量,其实因为多写不了几行。

现在我们使用上面的方法改写之前的代码:

import java.io.*;
public class Hello{
    	public static void main(String[] args) {
                String fileName="D:"+File.separator+"hello.txt";
        	File f=new File(fileName);
        	try{
            		f.createNewFile();
        	}catch (Exception e) {
            		e.printStackTrace();
        	}
   	 }
}

 看吧,只是多了一行而已,但是代码的跨平台性就增强了许多。

 

字节流和字符流

 

学习了简单的File类的知识,现在我们就可以在其之上进行更多的操作了。

比如说写入数据,从文件中读取数据。

下面是一个小例子:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class IOStream {
	/**
	 * 读取函数
	 * @param filename
	 */
	public void read(String filename){
		File f=new File(filename);
		try {
			InputStream ins=new FileInputStream(f);
			int i=ins.read();
			while(i!=-1){
				System.out.println("读取的字节码为:"+i);
				i=ins.read();

			}
			ins.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	/**
	 * 输出函数
	 * @return
	 */
	public String print(String filename){
		File f=new File(filename);
		String s="";
		try {
			@SuppressWarnings("resource")
			InputStream ins=new FileInputStream(f);
			byte[] printtest=new byte[ins.available()];//ins.available是取得输入流的长度。
			ins.read(printtest);//与ins.read();不一样。这个是从输入流中读取数据并把它写到byte[]中。
			s=new String(printtest);
			System.out.println(s);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			return "Error!";
		} catch (IOException e) {
			e.printStackTrace();
			return "Error!";
		}
		return s;
		
	}
	/**
	 * 写入函数
	 * @param message
	 */
	public void write(String message){
		try {
			OutputStream outs=new FileOutputStream("F:\\test.txt");
			//输出流中的数据“流”入到路径所在的文件中。
			byte[] iowrite=message.getBytes();
			outs.write(iowrite);
			//是从iowrite中读取数据并写入到输出流中。
			outs.flush();
			System.out.println("写入成功!");
			outs.close();
		}catch (IOException e) {
			e.printStackTrace();
		}
		
		
	}
	/**
	 * 加密函数
	 * @param args
	 */
	public void encrypt(String message){
		int i,j;
		try {
			byte[] iowrite=message.getBytes();
			int size=iowrite.length;
			byte[] msg1=new byte[size/2];
			OutputStream outs=new FileOutputStream("F:\\msg1.txt");
			for(i=0;i<(size/2);i++){
				msg1[i]=(byte) (iowrite[i]+1);
			}
			outs.write(msg1);
			outs.flush();
			outs.close();
			System.out.println("成功一半!");
			OutputStream newouts=new FileOutputStream("F:\\msg2.txt");
			byte[] msg2=new byte[size-(size/2)];
			for(j=0;i<size;i++,j++){
				msg2[j]=(byte) (iowrite[i]-1);
			}
			newouts.write(msg2);
			newouts.flush();
			System.out.println("写入成功!");
			newouts.close();
		}catch (IOException e) {
			e.printStackTrace();
		}
	}
	/**
	 * 解密函数
	 * @param args
	 */
	public void discrypt(String msg1,String msg2){
		int i,j;
		try {
			byte[] msg_1=msg1.getBytes();
			byte[] msg_2=msg2.getBytes();
			int size_1=msg_1.length;
			int size_2=msg_2.length;
			byte[] write=new byte[size_1+size_2];
			OutputStream outs=new FileOutputStream("F:\\msg.txt");
			for(i=0;i<size_1;i++){
				msg_1[i]=(byte) (msg_1[i]-1);
				write[i]=msg_1[i];
			}
			for(i=size_1,j=0;j<size_2;j++,i++){
				msg_2[j]=(byte) (msg_2[j]+1);
				write[i]=msg_2[j];
			}
			outs.write(write);
			outs.flush();
			System.out.println("写入成功!");
			outs.close();
		}catch (IOException e) {
			e.printStackTrace();
		}
	}
	public static void main(String[] args) {
		@SuppressWarnings("unused")
		String filename="F:\\IOStream.java";
		String msg_1="F:\\msg1.txt";
		String msg_2="F:\\msg2.txt";
		IOStream test =new IOStream();
		
		test.discrypt(test.print(msg_1),test.print(msg_2));
		
	}

}

 这上面还执行了一个字节层面的数据加密和解密,加密是将所有的字节码分为两份,一份字节码加一,一份字节码减一,然后分开存为两份文件。解密当然就是加密的反向操作啦!

然后我要承认一个错误,就是为了方便,我还是直接写的路径,没有用常量(0.0)。

 

然后写入数据还可以直接用Writer类:

/**
 * 字符流
 * 写入数据
 * */
import java.io.*;
public class hello{
    public static void main(String[] args) throws IOException {
        String fileName="D:"+File.separator+"hello.txt";
        File f=new File(fileName);
        Writer out =new FileWriter(f);
        String str="hello";
        out.write(str);
        out.close();
    }
}

如果你想向文件中追加内容,可以使用将上面的声明out的那一行换为:

Writer out =new FileWriter(f,true);

 同样的,用OutputStream类时,也可以改成如下代码来执行此操作:

OutputStream outs=new FileOutputStream("F:\\test.txt",true);

 如果想在文件中换行的话,需要使用“\r\n”;

比如将str 变为String str="\r\nhello";

这样文件追加的内容就会换行了。

 

那么相对称的,我们可以用Reader类来读取数据:

/**
 * 字符流
 * 从文件中读出内容
 * */
import java.io.*;
public class hello{
    public static void main(String[] args) throws IOException {
        String fileName="D:"+File.separator+"hello.txt";
        File f=new File(fileName);
        char[] ch=new char[100];
        Reader read=new FileReader(f);
        int count=read.read(ch);
        read.close();
        System.out.println("读入的长度为:"+count);
        System.out.println("内容为"+new String(ch,0,count));
    }
}

 读者可能会困扰InputStream(OutputStream)和Reader(Writer)的区别,那我们下面就来分析一下:

 

Reader(Writer)支持16位的Unicode字符输出(输入),而InputStream(OutputStream)支持8位的字符输出。

 

InputStream(OutputStream)和Reader(Writer)分别是I/O库提供的两套平行独立的等级机构。

 

InputStream和OutputStream是用来处理8位元的流。Reader和Writer是用来处理16位元的流。

 

而在Java语言中,byte类型是8位的,char类型是16位的,所以在处理中文时需要用Reader和Writer。

 

值得说明的是,在这两种等级机构下,还有一道桥梁InputStreamReader、OutputStreamWriter负责进行InputStream到Reader的适配以及OutputStream到Writer的适配。

 

java.io.Reader和java.io.InputStream组成了Java的输入类。Reader用于读入16位字符,也就是Unicode编码的肌肤;而InputStream用于读入ASCLL字符和二进制数据。

 

在Java中,有不同类型的Reader输入流对应不同的数据源:

               FileReader  用于从文件输入;

               CharArrayReader  用于从程序的字符数组输入;

               StringReader  用于从程序中的字符串输入;

               PipedReader  用于读取从另一个线程中的 PIpedWriter 写入管道的数据。

 

 相应的也有不同类型的 InputStream 输入流对应于不同的数据源:

               FileInputStream;

               ByteArrayInputStream;

               StringBufferInputStream;

               PipedInputStream。

另外,还有两种没有对应 Reader 类型的 InputStream 输入流:

               Socket 用于套接字;

               URLConnection  用于 URL 连接。

这两个类使用 getInputStream()来读取数据。

相应的,java.io.Writer和java.io.OutputStream 也有类似的区别。

 

提醒一下,当用read()方法读到文件末尾的时候会返回-1,正常情况下是不会返回-1的。

 

关于字节流和字符流的区别

实际上字节流在操作的时候本身是不会用到缓冲区的,是文件本身的直接操作的,但是字符流在操作的 时候下后是会用到缓冲区的,是通过缓冲区来操作文件的。

读者可以试着将上面的程序的最后一行关闭文件的代码注释掉,然后运行程序看看。你就会发现使用字节流的话,文件中已经存在内容,但是使用字符流时,文件中还是没有内容的,这个时候就要刷新缓冲区。

 

使用字节流好还是字符流好呢?

答案是字节流。首先因为硬盘上的所有文件都是以字节的形式进行传输或者保存的,包括图片、音乐等内容。但是字符只是在内存中才会存在,所以在开发中,字节流使用广泛。

 

管道流

管道流主要可以进行两个线程之间的通信。

PipedOutputStream  管道输出流

PipedInputStream 管道输入流

 

下面我们来验证一下管道流:

/**
 * 验证管道流
 * */
import java.io.*;
 
/**
 * 消息发送类
 * */
public class Send implements Runnable{
    private PipedOutputStream out=null;
    public Send() {
        out=new PipedOutputStream();
    }
    public PipedOutputStream getOut(){
        return this.out;
    }
    public void run(){
        String message="Hello , Java";
        try{
            out.write(message.getBytes());
        }catch (Exception e) {
            e.printStackTrace();
        }try{
            out.close();
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}
 
/**
 * 接受消息类
 * */
class Recive implements Runnable{
    private PipedInputStream input=null;
    public Recive(){
        this.input=new PipedInputStream();
    }
    public PipedInputStream getInput(){
        return this.input;
    }
    public void run(){
        byte[] b=new byte[1000];
        int len=0;
        try{
            len=this.input.read(b);
        }catch (Exception e) {
            e.printStackTrace();
        }try{
            input.close();
        }catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("接受的内容为 "+(new String(b,0,len)));
    }
}
/**
 * 测试类
 * */
class hello{
    public static void main(String[] args) throws IOException {
        Send send=new Send();
        Recive recive=new Recive();
        try{
//管道连接
            send.getOut().connect(recive.getInput());
        }catch (Exception e) {
            e.printStackTrace();
        }
        new Thread(send).start();
        new Thread(recive).start();
    }
}

 运行结果:

接受的内容为 Hello,Java

 

数据操作流DataOutputStream、DataInputStream类

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
 
public class DataOutputStreamDemo{
    public static void main(String[] args) throws IOException{
        File file = new File("d:" + File.separator + "hello.txt");
        char[] ch = { 'A', 'B', 'C' };
        DataOutputStream out = null;
        out = new DataOutputStream(new FileOutputStream(file));
        for(char temp : ch){
            out.writeChar(temp);
        }
        out.close();
    }
}

 A B C

 

现在我们在上面的例子的基础下,使用DataInputStream读出内容:

 

mport java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
 
public class DataOutputStreamDemo{
    public static void main(String[] args) throws IOException{
        File file = new File("d:" + File.separator + "hello.txt");
        DataInputStream input = new DataInputStream(new FileInputStream(file));
        char[] ch = new char[10];
        int count = 0;
        char temp;
        while((temp = input.readChar()) != 'C'){
            ch[count++] = temp;
        }
        System.out.println(ch);
    }
}

 输出结果:A B

 

I/O就先和大家论述到这里,在之后学习的更加完善时,我会及时跟进,增加此博文的内容,欢迎大家关注我,也欢迎大家提出意见和建议。

 

 

  • 大小: 23.1 KB
  • 大小: 15.4 KB
分享到:
评论

相关推荐

    JAVA_IO详解_包括讲解IO中各种流及其用法.pdf

    java IO流总结文档。总要总结了 java IO 流的主要基本操作和使用到的类及方法。对于入门比较有用,如果对 IO 流比较了解,就没必要看了。

    Java-IO流/Stream流总结

    内容:IO流及其分类、分类比较、转换流、缓存流、IO流异常处理、Stream流、Properties教程等。 适合人群:有编程基础及Java基础伙伴 适用场景:Java中的流是随处可见的,涉及文件的操作必须使用IO流,Stream流可以对...

    dbcp,c3p0,io

    内包含了数据库连接池的c3p0.jar及其依赖和dbcp.jar及其依赖.以及对IO流操作的jar包

    数据读写操作API(源码+jar包+文档)

    文件包含了jar包及其源码,提供了各种数据读写,IO流读写的API,省去了自己操作IO流和数据的繁琐,提供了许多方法供调用,可以用来学习或者用在数据操作或涉及IO操作的代码编写中,绝对有收藏价值!

    atom-flow:对haxe流构建工具的atom.io支持

    对haxe流构建工具的atom.io支持 积极发展 请注意,此软件包正在积极开发中,您一定会发现一些粗糙的地方和痛点。 欢迎提出问题,反馈和建议。 谢谢! 要求 从atom设置-&gt;安装安装这些 需要haxe包及其依赖项请参阅以...

    基于java+控制台+TXT文本实现学生成绩管理系统(高分课程设计)

    基于java+控制台+TXT文本实现学生成绩管理系统(高分课程设计)已获导师指导并通过的95分的高分期末大作业项目...(8)IO流形成文件保存/读入学生成绩 详见:https://blog.csdn.net/Timi2019/article/details/128351011

    基于java+swing+TXT文本实现学生成绩管理系统(高分课程设计)

    基于java+swing+TXT文本实现学生成绩管理系统(高分课程设计)已获导师指导并通过的95分的高分期末大作业项目,...(8)IO流形成文件保存/读入学生成绩 详见:https://blog.csdn.net/Timi2019/article/details/128351244

    java及spring基础知识pdf

    资源包含如下: 1,JAVA_IO详解_包括讲解IO中各种流及其用法.pdf 2,Java集合排序及java集合类详解.pdf 3,JDBC入门电子书.pdf 4,Spring源代码解析.pdf 5,第三章 Servlet 最佳实践.pdf

    Java 基础核心总结 +经典算法大全.rar

    节点流和处理流 Java IO 的核心类 File Java IO 流对象 字节流对象InputStream OutputStream 字符流对象Reader Writer 字节流与字符流的转换新潮的 NIO 缓冲区(Buffer)通道(Channel) 示例:文件拷贝案例 BIO 和 NIO ...

    Java开发详解.zip

    031205_【第12章:JAVA IO】_内存操作流笔记.pdf 031206_【第12章:JAVA IO】_管道流笔记.pdf 031207_【第12章:JAVA IO】_打印流笔记.pdf 031208_【第12章:JAVA IO】_System类对IO的支持笔记.pdf 031209_【第12章...

    Claunia.IO:.NET库用于管理基础文件系统的扩展属性(xattrs)和文件派生(aka备用数据流)

    它目前正在大量开发中,需要一些时间才能完成。 目标操作系统 适用于台式机的Windows NT(XP,Vista,7、8和10) Linux FreeBSD及其衍生版本(PC-BSD等) Mac OS X 可能定位的操作系统 Solaris(需要在其上运行...

    2023Java高频面试题

    IO流:Java中常用的文件读写、序列化和反序列化等操作。 多线程编程:线程的基本概念、线程同步、线程安全、死锁等问题。 JDBC:Java与数据库的交互,连接池的使用等。 Spring框架:Spring框架的基础概念、IOC容器、...

    dotnet-code-coverage-badge:生成代码覆盖标志的GitHub动作

    然后,它会生成shield.io数据,如果给出了要旨和文件名,则shields.io 要求为了使此操作生效,工作流中必须有一个opencover.xml文件,并且必须将其路径指定为输入参数。 在.NET中制作此opencover.xml非常简单。 您...

    C#二维三维图形绘制工程实例宝典

    书名 版权 前言 第一部分 C#的基本数据类型、数组类型和图形基础第1章 C#语言基础 1.1 数据类型 1.1.1 简单类型 1.1.2 结构类型 1.1.3 枚举类型 1.1.4 数组类型 ...10.4 一些常见的问题及其解决方案 参考文献

    C#二维三维图形绘制工程实例宝典 随书光盘

    第2章 图形基础 34 2.1 笔和画刷 34 2.1.1 pen 类 34 2.1.2 brush 类 35 2.2 基本图形形状 37 2.2.1 点 37 2.2.2 直线和曲线 37 2.2.3 矩形、椭圆形和圆弧形 40 ...10.4 一些常见的问题及其解决 方案 643

    三步学会Java Socket编程

     服务器,使用ServerSocket监听指定的端口,端口可以随意指定(由于1024以下的端口通常属于保留端口,在一些操作系统中不可以随意使用,所以建议使用大于1024的端口),等待客户连接请求,客户连接后,会话产生;...

    leetcode答案-theEmbeddedNewTestament.github.io:theEmbeddedNewTestament.gi

    给定一个矩阵及其中心坐标,画圆 在原始字节流缓冲区中查找 32 位帧起始序列 内存跟踪器挂钩到 glibc 库以跟踪动态内存分配,包括统计信息 给定一组角度和这些角度的一组电压,现在有一个新的角度进入,计算它的电压...

    通俗易懂之Flink DataStream API开发

    l 了解流处理的基本概念 l 掌握DataStream的算子操作(source、transformation、sink) l 掌握水印使用及其原理 l 掌握状态和容错机制 l 掌握异步io的使用和原理 l 掌握端对端一次性语义的使用和原理 l 掌握...

    Skyreach:用于 JPEG2000 结构遍历和压缩域操作的库

    Skyreach 可用于从 JPEG2000 压缩图像中提取数据并基于此数据创建新图像,仅使用基于 IO 的操作。 应用包括: jp2extract (work-in-progress):提取以下组合: 图像的低分辨率子集。 平铺图像中的特定平铺。 颜色...

Global site tag (gtag.js) - Google Analytics