java流入流出实验小结,Java IO流小结与常用类之间的相互转换

一、简介

Java中I/O操作主要是指使用Java进行输入,输出操作. Java所有的I/O机制都是基于数据流进行输入输出,这些数据流表示了字符或者字节数据的流动序列,也就是大家习惯称呼的字节流和字符流。

网上有个很好的比喻:

数据流是一串连续不断的数据的集合,就象水管里的水流,在水管的一端一点一点地供水,而在水管的另一端看到的是一股连续不断的水流。数据写入程序可以是一段、一段地向数据流管道中写入数据,这些数据段会按先后顺序形成一个长的数据流。对数据读取程序来说,看不到数据流在写入时的分段情况,每次可以读取其中的任意长度的数据,但只能先读取前面的数据后,再读取后面的数据(不能随机读取)。不管写入时是将数据分多次写入,还是作为一个整体一次写入,读取时的效果都是完全一样的。

简而言之:数据流是一组有序,有起点和终点的字节的数据序列。包括输入流和输出流。

当程序需要读取数据的时候,就会建立一个通向数据源的连接,这个数据源可以是文件,内存,或是网络连接。类似的,当程序需要写入数据的时候,就会建立一个通向目的地的连接。

字节流:数据流中最小的数据单元是字节ASCII 编码  2) 字符流:数据流中最小的数据单元是字符, Java中的字符是Unicode编码,一个字符占用两个字节。

二、概览

Java.io包中最重要的就是5个类和一个接口。5个类指的是File、OutputStream、InputStream、Writer、Reader;一个接口指的是Serializable。

Java I/O主要包括如下3层次:

流式部分——最主要的部分。如:OutputStream、InputStream、Writer、Reader等

非流式部分——如:File类、RandomAccessFile类和FileDescriptor等类

其他——文件读取部分的与安全相关的类,如:SerializablePermission类,以及与本地操作系统相关的文件系统的类,如:FileSystem类和Win32FileSystem类和WinNTFileSystem类。

主要类如下:

File(文件特征与管理):用于文件或者目录的描述信息,例如生成新目录,修改文件名,删除文件,判断文件所在路径等。

InputStream(字节流,二进制格式操作):抽象类,基于字节的输入操作,是所有输入流的父类。定义了所有输入流都具有的共同特征。

OutputStream(字节流,二进制格式操作):抽象类。基于字节的输出操作。是所有输出流的父类。定义了所有输出流都具有的共同特征。

Reader(字符流,文本格式操作):抽象类,基于字符的输入操作。

Writer(字符流,文本格式操作):抽象类,基于字符的输出操作。

RandomAccessFile(随机文件操作):它的功能丰富,可以从文件的任意位置进行存取(输入输出)操作。

f33256569e20aee67a1e2ec38542e670.png

三、用法用例

1.I/O的开始——File

I/O流本质是对文件的处理。Java提供了对文件的常见操作,创建,重命名,删除

创建:

createNewFile()在指定位置创建一个空文件,成功就返回true,如果已存在就不创建,然后返回false。

mkdir()  在指定位置创建一个单级文件夹。

mkdirs()  在指定位置创建一个多级文件夹。

renameTo(File dest)如果目标文件与源文件是在同一个路径下,那么renameTo的作用是重命名, 如果目标文件与源文件不是在同一个路径下,那么renameTo的作用就是剪切,而且还不能操作文件夹。

删除:

delete()  删除文件或者一个空文件夹,不能删除非空文件夹,马上删除文件,返回一个布尔值。

deleteOnExit()jvm退出时删除文件或者文件夹,用于删除临时文件,无返回值。

判断:

exists()  文件或文件夹是否存在。

isFile()  是否是一个文件,如果不存在,则始终为false。

isDirectory()  是否是一个目录,如果不存在,则始终为false。

isHidden()  是否是一个隐藏的文件或是否是隐藏的目录。

isAbsolute()  测试此抽象路径名是否为绝对路径名。

获取:

getName()  获取文件或文件夹的名称,不包含上级路径。

getAbsolutePath()获取文件的绝对路径,与文件是否存在没关系

length()  获取文件的大小(字节数),如果文件不存在则返回0L,如果是文件夹也返回0L。

getParent()  返回此抽象路径名父目录的路径名字符串;如果此路径名没有指定父目录,则返回null。

lastModified()获取最后一次被修改的时间。

文件夹相关:

static File[] listRoots()列出所有的根目录(Window中就是所有系统的盘符)

list()  返回目录下的文件或者目录名,包含隐藏文件。对于文件这样操作会返回null。

listFiles()  返回目录下的文件或者目录对象(File类实例),包含隐藏文件。对于文件这样操作会返回null。

list(FilenameFilter filter)返回指定当前目录中符合过滤条件的子文件或子目录。对于文件这样操作会返回null。

listFiles(FilenameFilter filter)返回指定当前目录中符合过滤条件的子文件或子目录。对于文件这样操作会返回null。

2.InputStream——输入流

他是一个抽象类,常用子类FileInputStream。核心方法read(),包含三个重载方法;close(),流使用结束后必须关闭!!!

2. 读入方法:read

跟读入相关的方法是这个类的核心方法。有3种重载的形式,下面分别介绍。

2.1 read()

1

public abstract int read()throws IOException

读取输入流的下一个字节。这是一个抽象方法,不提供实现,子类必须实现这个方法。该方法读取下一个字节,返回一个0-255之间的int类型整数。如果到达流的末端,返回-1. 调用该方法的时候,方法阻塞直到出现下列其中一种情况:1)遇到流的尾部(end of the stream)。2)有数据可以读入。3)抛出异常。 面向字节的操作时,可能需要像这样比较底层的字节操作。我们也可以一次读入多个字节,使用下面的重载形式。

2.2 read(byte[] b)

1

public int read(byte b[])throws IOException

试图读入多个字节,存入字节数组b,返回实际读入的字节数。如果传递的是一个空数组(注意数组长度可以为0,即空数组。比如 byte[] b = new byte[0]; 或者byte[] b = {};)那么什么也没读入,返回0.

如果到达流尾部,没有字节可读,返回-1;如果上面两种情况都没有出现,并且没有I/O错误,则至少有1个字节被读入,存储到字节数组b中。实际读入的第一个字节存在b[0],往后一次存入数组,读入的字节数最多不能超过数组b的长度。如果读入的字节数小于b的长度,剩余的数组元素保持不变。具体地,如果读入的字节数为k,则k个字节分别存在 b[0]到b[k-1],而b[k]到b[b.length-1]保持原来的数据。

2.3 read (byte[] b, int off, int len)

1

public int read(byte[] b,int off,int len)throws IOException

这个方法跟上一个功能类似,除了读入的数据存储到b数组是从off开始。len是试图读入的字节数,返回的是实际读入的字节数。如果len=0,则什么也不读入,返回0;如果遇到流尾部,返回-1.否则至少读入一个字节。

假设实际读入k个字节,则k个字节分别存储在b[off]到b[off+k-1],而b[off+k]往后的元素保持不变。b[off]之前也保持不变。

1

2

3

public int read(byte b[])throws IOException {

return read(b,0, b.length);

}

解析来看一下第三个read方法的源代码:

public int read(byte b[], int off, int len) throws IOException {

if (b == null) { // 检测参数是否为null

throw new NullPointerException();

} else if (off < 0 || len < 0 || len > b.length - off) {

throw new IndexOutOfBoundsException(); // 数组越界检测

} else if (len == 0) {

return 0; //如果b为空数组,返回0

}

int c = read(); // 调用read()方法获取下一个字节

if (c == -1) {

return -1;

} // 遇到流尾部,返回-1

b[off] = (byte)c; //读入的第一个字节存入b[off]

int i = 1; // 统计实际读入的字节数

try {

for (; i < len ; i++) { // 循环调用read,直到流尾部

c = read();

if (c == -1) {

break;

}

b[off + i] = (byte)c; // 一次存入字节数组

}

} catch (IOException ee) {

}

return i; // 返回实际读入的字节数

}

我们看到方法可能抛出IOException异常,如果第一个字节无法读入且原因不是到达流尾部,或者流已经被关闭,或者其他IO错误,则抛出这个异常。

上面三个读入方法都可能出现阻塞,在2.1中已经介绍了阻塞解除的条件。理解这三个方法很重要的一点是:方法只是尝试读入我们想要的字节数,但是能否成功, 会受到数据源的影响。另外一点就是读入的数据存到哪里,第一个方法作为返回值,第二、三个方法存入到指定数组的指定位置,返回的是实际读入的字节数。后两个方法真正的读入工作都是通过调用抽象方法read()来完成的,资格抽象方法在子类中实现。

3.OutputStream——输出流

抽闲类,常用子类FileOutputStream,ByteArrayOuputStream,核心方法write(),也包含了3个重载方法;close(),流使用结束后必须关闭!!!onflush(),刷新此输出流并强制写出所有缓冲的输出字节。

(1) write(byte[]),写入一个byte数组的内容;

(2)write(byte[],int off,int len)          将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。

(3)write(int b)  将指定的字节写入到输出流

示例:复制文件

public static void testMethod2() {

51

52 File fileIN = new File("d:/TEST/MyFile.jpg"); //定义输入文件

53 File fileOUT = new File("d:/TEST/MyFileCopy.jpg"); //定义输出文件

54

55 FileInputStream fis = null;

56 FileOutputStream fos = null;

57

58 try {

59

60 fis = new FileInputStream(fileIN); //输入流连接到输入文件

61 fos = new FileOutputStream(fileOUT); //输出流连接到输出文件

62

63 byte[] arr = new byte[2048]; //该数组用来存入从输入文件中读取到的数据

64 int len; //变量len用来存储每次读取数据后的返回值

65

66 while( ( len=fis.read(arr) ) != -1 ) {

67 fos.write(arr, 0, len);

68 }//while循环:每次从输入文件读取数据后,都写入到输出文件中

69

70 } catch (IOException e) {

71 e.printStackTrace();

72 }

73

74 //关闭流

75 try {

76 fis.close();

77 fos.close();

78 } catch (IOException e) {

79 e.printStackTrace();

80 }

81 }

File相当于管道,InputStream和OutPutStream相当于2股水流,字节流和字符流沿着管道从文件流出到程序或者从程序流入到文件。

四、常见类之间的转换

1.String转字节流

String s="abc";

byte[] b=s.getbyte();

2.byte[ ]转String

String s=new String(byte[]);

3.byte[]写入到输入流InputStream

(1)byte[]转换为InputStream

InputStream sbs = new ByteArrayInputStream(byte[] buf);

(2)InputStream转换为InputStreambyte[]

ByteArrayOutputStream swapStream = new ByteArrayOutputStream();

byte[] buff = new byte[100]; //buff用于存放循环读取的临时数据

int rc = 0;

while ((rc = inStream.read(buff, 0, 100)) > 0) {

swapStream.write(buff, 0, rc);

}

byte[] in_b = swapStream.toByteArray(); //in_b为转换之后的结果

4.byte[ ]转换输出流OutputStream——write(byte[ ])

五、BufferedOutputStream 缓冲的输出流

它提供了和FileOutputStream类同样的写操作方法,不同的是:

它把所有的输出先全部写入缓冲区中,当缓冲区满了或者该输出流关闭的时候,它再一次性的输出到流。或者也可以显式的调用flush() 方法主动将缓冲区输出到流。通过减小系统写数据的时间而提高了性能。

// 构造函数,接收的是一个**节点流**

BufferedOutputStream(OutputStream out)

BufferedOutputStream(OutputStream out, int size)

它的使用方式:

File file = new File("G:/a2.txt");

FileOutputStream out = new FileOutputStream(file);

BufferedOutputStream bufferedOut =  new BufferedOutputStream(out);

bufferedOut.write(byteData);

//  需要注意的是,如果下面的两句不写上,是不会写入到文件中去的,因为此时要写入的数据还在缓冲区

bufferedOut.flush(); // 将缓冲区的字节写入到文件中,然后清空缓冲区

bufferedOut.close(); // 关闭的时候也会检查缓冲区,缓冲区有数据,会先写入文件清空缓冲区,再关闭。

其他,Reader和Writer字符流操作在此不再详细介绍,感兴趣可以在http://tool.oschina.net/apidocs/apidoc?api=jdk-zh,查看官方API文档,获取用法。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值