第八章 IO(输入输出)
2.引子
马克-to-win:(视频下载) (全部书籍)对我们编程人员来说,经常需要和IO(输入/输出)系统打交道。包括文件、控制 台、网络连接。神奇的是:java的IO包里的各种各样的类竟然把上面的所有IO情况(文件、控制台、网络连接)都能一把抓轻松搞定。这章我们学文件,控 制台, 下章我们学网络连接。
马克-to-win:(视频下载) (全部书籍)很多老司机还搞不清什么是I什么是O。很简单,我有个土办法。以内存为单位,数据进内存叫In,出内存叫Out。读文件,是数据从硬盘进到内存,所以用in类型流来处理。
马 克-to-win:(视频下载) (全部书籍)当时Sun为什么起名叫流?很多初学的同学有这个疑问,这一流就把他流晕了, 我小学数学老师让我们算张三走路的速度,谁追谁,他一动,像个流一样, 我就晕了。现在我跟大家说,举个例子,这里比如有个文件,java的处理方法是:把硬盘上的文件和内存中我们的一个流绑在一起,当你一个一个的顺序的读流 中的每个字节一遍后,你发现你无形中读了硬盘上的文件一遍。通过这样的方法,你不就能操作硬盘上的文件了吗?当你一个一个的顺序的读流中的每个字节时,像 不像你人不动,站在那里,瞪着眼睛,看着一个小孔,而有一串字节像流水一样,经过小孔。知道Sun为什么当时起名叫“流”了吧!
java当中有两种流,一种是字节流(byte stream): (视频下载) (全部书籍)以1字节(8-bit)为单位进行读/写,一次处理一个字节。另一种是字符流(character stream):,以字符为单位,一次处理一个字符。
马克-to-win:(视频下载) (全部书籍)注意如果当遇到英文时,字符流足够聪明,一次就读一个字节,如遇到中文,一次读两个字节。比如a就占一个字节,即97.见下面的例子。我们摘录一段java官方文档:Each invocation of one of an InputStreamReader's read() methods may cause one or more bytes to be read from the underlying byte input stream.
第一节 字节流
本节我们只讲字节流,字符流将来再讲。马克to-win:Sun设计者决定字节流中与输出有关的所有类都从OutputStream继承,而与输入有关的所有类都从InputStream继承。
既
然输出字节流中所有类都从
OutputStream继承,每个类都有自己专门的功能。(否则继承出来有什么用呢?)我们常用的输出字节流都有PrintStream,
FileOutputStream,BufferedOutputStream,DataOutputStream,
ObjectOutputStream
。。。下面我们一一给予介绍,更多未提到的可去文档中查阅,大同小异。
1.1 FileOutputStream的用法 (视频下载) (全部书籍)
FileOutputStream是OutputStream的继承类,从字面上就可看出,它的主要功能就是能向磁盘上写文件。write方法会把字节一个一个的写入磁盘中。
例:1.1.1
import java.io.*;
public class TestMark_to_win {
public static void main(String args[]) throws Exception {
FileOutputStream f = new FileOutputStream("c:/4.txt");
/*后面的write方法里面调用了c语言里面open方法。里面有native void open(String name)
*/
byte aa = 97;
f.write(aa);
char bb = 'b';
/*没有write(char),只能机器自动转从char到int*/
f.write(bb);
int cc = 99;
f.write(cc);
// String kk1="97";
// f.write(kk1);//error, because FileOutputStream does not have
// write(String) method.must use PrintStream.
}
}
1.2 PrintStream的用法 (视频下载) (全部书籍)
1.3 BufferedOutputStream的用法 (视频下载) (全部书籍)
马克-to-win:BufferedOutputStream
顾名思义就是它有一个内部的buffer(缓存),当写数据时,可以批量的写。它的工作原理和BufferedIputStream一样,包括例子,请参考下文的BufferedInputStream。
1.4 DataOutputStream的用法 (视频下载) (全部书籍)
马克-to-win:一定要注意DataOutputStream 与DataInputStream必须配合使用,以便将基本数据类型(int,char,long,String等)写入一个数据流。详细讲解请见下面的DataInputStream部分。
1.5 ObjectOutputStream的用法 (视频下载) (全部书籍)
马
克-to-win:顾名思义,ObjectOutputStream一定是用来往输出流上写用户自定义的对象的。比如数据库中某表的一行数据对应一个对
象,这时可通过这种方法存在硬盘上。一定要注意ObjectOutputStream与ObjectInputStream必须配合使用,且按同样的顺
序。例子参见ObjectInputStream那部分的描述。
2.输入流
既
然输入字节流中所有类都从InputStream继承,每个类都有自己专门的功能(否则继承出来有什么用呢?)我们常用的输入字节流都有
InputStream,FileInputStream,BufferedInputStream,DataInputStream,
ObjectInputStream。。。下面我们一一给予介绍,更多未提到的可去文档中查阅,大同小异。
2.1 InputStream的用法 (视频下载) (全部书籍)
2.2 FileInputStream的用法 (视频下载) (全部书籍)
FileInputStream是InputStream的继承类,从字面上就可看出,它的主要功能就是能从磁盘上读入文件。read方法会一个一个字节的从磁盘往回读数据。
例:2.2.1
import java.io.*;
public class TestMark_to_win {
public static void main(String args[]) throws Exception {
int size;
FileInputStream f1 = new FileInputStream("c:/1.txt");
/*Returns the number of bytes that can be read from this file input
stream without blocking.*/
size = f1.available();
for (int i = 0; i < size; i++) {
/*Reads a byte of data from this input stream. This method blocks
if no input is yet available. Returns: the next byte of data, or
-1 if the end of the file is reached.*/
System.out.println((char) f1.read());
}
int size2;
FileInputStream f2 = new FileInputStream("c:/1.txt");
size2 = f2.available();
for (int i = 0; i < size2; i++) {
/* you use the next statement, only int value can be printed out. */
System.out.println(f2.read());
}
}
}
我的c盘下的1.txt文本是:
ab我们ab
程序运行结果是:
a
b
?
?
?
?
a
b
97
98
206
210
195
199
97
98
例:2.2.2(下面是一个较笨的拷贝程序,初学者好理解)
import java.io.*;2.3 BufferedInputStream的用法 (视频下载) (全部书籍)
马克-to-win:BufferedInputStream
顾名思义就是它有一个内部的buffer(缓存),它的read方法表面上看,虽然是只读了一个字节,但它是开始时猛然从硬盘读入一大堆字节到自己的缓
存,当你read时,它是从缓存读进一个字节到内存。而前面讲的FileInputStream字节流,read时,都是真正每个字节都从硬盘到内存,是
很慢的。为什么?请研究硬盘的结构!下面的两个例子,一个是FileInputStream的read生读进来的,另一个是BufferedInputStream的只能read,你比较一下读的时间,差距蛮大的!
例:2.3.1
import java.io.*;
public class TestMark_to_win {
public static void main(String args[]) throws FileNotFoundException,
IOException {
FileInputStream fis = new FileInputStream("c:/2.txt");
long t = System.currentTimeMillis();
int c;
while ((c = fis.read()) != -1) {}
fis.close();
t = System.currentTimeMillis() - t;
System.out.println("遍历文件用了如下时间:" + t);
}
}
遍历文件用了如下时间:453
例:2.3.2
import java.io.*;
public class TestMark_to_win {
public static void main(String args[]) throws FileNotFoundException,
IOException {
FileInputStream fis = new FileInputStream("i:\\2.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
long t = System.currentTimeMillis();
int c;
/*even though the next read() also read one byte, but because
BufferedInputStream has an internal buffer,when first time to read,
it will read in a whole buffer of byte from hard disk, then digest
these bytes one by one in memory */
while ((c = bis.read()) != -1) {}
fis.close();
t = System.currentTimeMillis() - t;
System.out.println("遍历文件用了如下时间:" + t);
}
}
下面的例子讲述BufferedInputStream的read(byte b[], int off, int len)的用法。即真正的批量读入。正好前面讲到BufferedOutputStream时,还欠大家一个例子。
例:2.3.3
import java.io.*;
public class TestMark_to_win {
public static void main(String[] args) {
String source = "c:\\2.txt";
String dest = "c:\\2_copy.txt";
try {
FileInputStream fis = new FileInputStream(source);
BufferedInputStream bis = new BufferedInputStream(fis);
FileOutputStream fos = new FileOutputStream(dest);
BufferedOutputStream bos = new BufferedOutputStream(fos);
int readcount;
byte[] readbyte = new byte[256];
/* public synchronized int read(byte b[], int off, int len) Reads
bytes from this byte-input stream into the specified byte array,
starting at the given offset.
@param b destination buffer.
@param off offset at which to start storing bytes.
@param len maximum number of bytes to read.
@return the number of bytes read, or <code>-1</code> if the end
of the stream has been reached.
@exception IOException if an I/O error occurs.*/
while ((readcount = bis.read(readbyte, 0, readbyte.length)) != -1) {
bos.write(readbyte, 0, readcount);
}
bis.close();
bos.close();
System.out.println("复制完毕!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
结果是:
复制完毕!
2.4 DataInputStream的用法 (视频下载) (全部书籍)
马
克-to-win:DataInputStream顾名思义:就是专门用来读各种各样的数据的,比如(int,char,long等),一定要注意
DataOutputStream
与DataInputStream配合使用,而且二者读写的顺序要一样,可以参照下面的例子。
2.5 ObjectInputStream的用法 (视频下载) (全部书籍)
马克-to-win:ObjectInputStream顾名思义就是可以从流中读入一个用户自定义的对象。一定要注意ObjectOutputStream与ObjectInputStream必须配合使用,且按同样的顺序。
输出结果是:
name:张三 id:1
name:李四 id:2
第二节 File类
马 克-to-win:sun公司设计File类,本身不能用来读数据或写数据。(要想读写数据,必须和其它io流的类配合使用,比如 FileInputStream等)File类的功能就是对磁盘上的文件或目录做一些非读写方面的工作,比如看看文件在哪个目录,哪天创建的,创建个新空 文件等。
例:2.1.1例:2.1.2
import java.io.*;
public class TestMark_to_win {
public static void main(String[] args) {
File path = new File("c:/");
/*Returns an array of strings naming the files and directories .*/
String[] list = path.list();
for (int i = 0; i < list.length; i++)
System.out.println(list[i]);
}
}
结果是:
$360Section
1.txt
2.txt
2_copy.txt
3.txt
360Rec
360SANDBOX
360安全浏览器下载
4.txt
91UserData
Adobe
AUTOEXEC.BAT
AVScanner.ini
BlueStacks_Green
boot.ini
bootfont.bin
Config.Msi
CONFIG.SYS
data.txt
dell
desktop.ini
Documents and Settings
Drivers
EasyGameUserData
FFOutput
InstallConfig.ini
IO.SYS
KPCMS
KwDownload
MSDOS.SYS
MSOCache
my_vod_caching
NTDETECT.COM
ntldr
out.txt
pagefile.sys
ppsfile
Program Files
QMBackup
QMDownload
RECYCLER
screenshot.png
SecurityScanner.dll
SogouPY
StormMedia
System Volume Information
temp
uacdump
vcredist_x86.log
WINDOWS
例:2.1.3(初学者可略过)
import java.io.*;
class MyFilenameFilter implements FilenameFilter {
/*public boolean accept(File dir,String name) Tests if a specified file
should be included in a file list.\u00A0
Parameters: dir - the directory in which the file was found. qixy: dir is
the caller in the dir.list(myFilenameFilter) name - the name of the
file.\u00A0 Returns: true if and only if the name should be included in
the file list; false otherwise. */
public boolean accept(File dir1, String name) {
System.out.println("here" + dir1.getAbsoluteFile());
System.out.println(name + "hereend");
boolean flag = (name.indexOf(".txt") != -1);
return flag;
}
}
public class TestMark_to_win {
public static void main(String[] args) throws IOException {
File dir = new File("c:");
MyFilenameFilter myFilenameFilter = new MyFilenameFilter();
/*String[] list (FilenameFilter filter) Returns an array of strings
naming the files and directories in the directory denoted by this
abstract pathname that satisfy the specified filter. 马克-to-win: if dir has
10 files. list method will call accept(File dir, String name1) 10
times, name1 is the\u00A0 name of one of the 10 files which is inside
this directory.\u00A0*/
String[] names = dir.list(myFilenameFilter);
for (int i = 0; i < names.length; i++) {
System.out.println(names[i]);
}
}
}
result is:
herec:\
$360Sectionhereend
herec:\
1.txthereend
herec:\
InstallConfig.inihereend
herec:\
my_vod_cachinghereend
herec:\
StormMediahereend
herec:\
System Volume Informationhereend
herec:\
temphereend
herec:\
test.txthereend
herec:\
uacdumphereend
herec:\
vcredist_x86.loghereend
herec:\
WINDOWShereend
1.txt
1_c.txt
2.txt
2_copy.txt
3.txt
4.txt
data.txt
out.txt
test.txt
第三节 字符流
本节我们只讲字符流。马克to-win:Sun设计者决定字符流中与输出有关的所有类都从Writer继承,而与输入有关的所有类都从Reader继承。
既
然输出字符流中所有类都从
Writer继承,每个类都有自己专门的功能。(否则继承出来有什么用呢?)我们常用的输出字符流都有FileWriter,PrintWriter
。。。下面我们一一给予介绍,更多未提到的可去文档中查阅,大同小异。
1.1 FileWriter的用法 (视频下载) (全部书籍)
FileWriter是Writer的继承类,从字面上就可看出,它的主要功能就是能向磁盘上写文件。write方法会把字符一个一个的写入磁盘中。
例:1.1.1
import java.io.*;
public class TestMark_to_win {
public static void main(String[] args) throws IOException {
File file = new File("c:\\test.txt");
FileWriter fw = new FileWriter(file);
/*void java.io.OutputStreamWriter.write(int c) throws IOException
Writes a single character.
Parameters:
c int specifying a character to be written*/
fw.write(97);
/*void java.io.Writer.write(String str) throws IOException
Writes a string.
Parameters:
str String to be written
*/
fw.write("this is 我们");
fw.close();
}
}
1.2 PrintWriter的用法 (视频下载) (全部书籍)
结果是:
output我们
output你们
2.输入流
既 然输入字符流中所有类都从Reader继承,每个类都有自己专门的功能。(否则继承出来有什么用呢?)我们常用的输入字符流都有StringReader,FileReader,BufferedReader,InputStreamReader 。。。下面我们一一给予介绍,更多未提到的可去文档中查阅,大同小异。
2.1 StringReader的用法 (视频下载) (全部书籍)
import java.io.*;
public class TestMark_to_win {
public static void main(String args[]) throws Exception {
// /////from multiline string to StringReader, then to console
String s, s1 = new String();
s = "你们" + "他们a我们" + "\n";
System.out.println(s);
/* A character stream whose source is a string. */
StringReader in2 = new StringReader(s);
int c;
/*in2.read() Read a single character,(qixy: two bytes 或1个字节, so can
handle chinese). or -1 if the end of the stream has been reached.
Returns: The character read */
while ((c = in2.read()) != -1) {
System.out.println((char) c);
}
}
}
结果:
你们他们a我们
你
们
他
们
a
我
们
2.2 FileReader的用法 (视频下载) (全部书籍)
FileReader是Reader的继承类,从字面上就可看出,它的主要功能就是能从磁盘上读入文件。read方法会一个一个字符的从磁盘往回读数据。
例:2.2.1
import java.io.*;
public class TestMark_to_win {
public static void main(String args[]) throws Exception {
/*public int read()
throws IOException
Reads a single character.
Overrides:
read in class Reader
Returns:
The character read, or -1 if the end of the stream has been reached
Throws:
IOException - If an I/O error occurs */
int ii;
FileReader in = new FileReader("c:/1.txt");
while ((ii = in.read()) != -1) {
System.out.println(ii);
}
in.close();
FileReader in1 = new FileReader("c:/1.txt");
while ((ii = in1.read()) != -1) {
System.out.println((char)ii);
}
in1.close();
}
}
结果:
97例:2.2.2(一个简单的拷贝方法,初学者方便理解)
import java.io.*;2.3 BufferedReader的用法 (视频下载) (全部书籍)
马克-to-win:BufferedReader和BufferedInputStream差不多,只不过一个处理字符,一个处理字节。buffer(缓存)什么的原理都是一样的。
import java.io.*;
public class TestMark_to_win {
public static void main(String args[]) throws Exception {
/* from file to string then to "multiline string" then to console. */
String s2, s3 = new String();
/*Creates a new FileReader, given the name of the file to read
from.BufferedReader(Reader in) Create a buffering character-input stream
that uses a default-sized input buffer.*/
BufferedReader in = new BufferedReader(new FileReader("c:/4.txt"));
/*readLine is a method from BufferedReader: Read a line of text.
Returns: A String containing the contents of the line, not including
any line-termination characters, or null if the end of the stream has
been reached */
while ((s2 = in.readLine()) != null) {
s3 += s2 + "\n";
}
System.out.println(s3);
in.close();
}
}
结果:
qi hello bye97我们import java.io.*;
public class TestMark_to_win {
public static void main(String args[]) throws Exception {
// /////////////////////// from StringReader to file:
String s = "你们" + "\n" + "他们我们" + "\n";
String s1 = "";
StringReader in2 = new StringReader(s);
in2.reset();
BufferedReader in4 = new BufferedReader(in2);
while ((s1 = in4.readLine()) != null) {
System.out.println("output" + s1);
}
}
}
结果:
output你们
output他们我们
2.4 InputStreamReader的用法 (视频下载) (全部书籍)
马
克-to-win:InputStreamReader
从文字上分析:InputStream是字节流的意思,Reader是字符流的意思。InputStreamReader这个类就是用来把字节流转换成字符流的。System.in代表控制台输入。它天生是个字节流。参见我前面写的InputStream小节的例:2.1.1,
我们发现如果向控制台输入中文,控制台是处理不了的,但这时如果我们用InputStreamReader这个工具转换一下,问题就解决了。下一章我们要
讲的网络传输,天生也是以字节形式进行的,所以字节流和字符流之间也必然转换一下。
import java.io.*;
public class TestMark_to_win {
public static void main(String args[]) throws Exception {
// ////////////////from console to string,\u00A0
System.out.println("from console to string ");
/*An InputStreamReader is a bridge from byte streams to
character streams: It reads bytes and decodes them into characters
using a specified charset. The charset that it uses may be specified by
name or may be given explicitly, or the platform's default charset may
be accepted. InputStreamReader(InputStream in) Create an
InputStreamReader that uses the default charset.
*/
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
String stdinS;
stdinS = stdin.readLine();
System.out.println(stdinS);
}
}
结果是:
from console to string
我们正在学java
我们正在学java
作业:
1) 做一个拷贝程序,它能拷贝gif或exe文件。
2)判断d:\tmp\1.txt这个文件是否为directory,file,可读?可写?(提示:File
f1,f1.isDirectory(),f1.isFile(),f1.canRead(),f1.canWrite().
3)
从命令行输入参数判断此文件是否为普通文件,如是打印出来内容。(提示:for(int
i=0;i<args.length;i++) {l.add(args[i]);} 先用File, 再用FileReader.
4) 把你在Console
中敲入的几行字符添加到一个文件的最后。(提示:FileWriter(String fileName,
boolean append)
敲入“end”,返回,
while(!(temp=br.readLine()).equals("end")){)