字节流是以字节作为流中元素的基本类型,每次读或者写的最小单位是一个字节,
字节输入流类是InputStream类以及子类,输出流是OutputStream以及子类。
字符流是以字符作为流中元素的基本类型,每次读写的最小单位是一个字符,
即2字节的Unicode码,字符流融合了编码表,字符输入流为Reader类以及其子类,输出流类是Writer以及其子类。
用IO流要明确源和目的:
源:输入流 InputStream Reader
目的:输出流OutputStream Writer
操作的数据是否是纯文本:
是:字符流
不是:字节流
二进制格式只要不能确定是纯文本的用: InputStream, OutputStream
是文件用 FileInputStream, FileOutputStream, FileReader, FileWriter
FileReader和FileInputStream用的时候文件必须已经存在在指定目录下
要格式化输出用 PrintStream, PrintWriter
是字节数组 byte[]用ByteArrayInputStream, ByteArrayOutputStream
遇到字节和字符数组,我们一般把他们转化为String,下面是String的4个构造方法
public String(byte[] bytes)
public String(byte[] bytes,int offset,int length)
public String(char[] value)
public String(char[] value,int offset,int count)
String可以通过下面2个方法转化成字节和字符数组:
public byte[] getBytes()
char[] toCharArray()
对象的输入输出用ObjectInputStream, ObjectOutputStream
进程间的通信用PipeInputStream, PipeOutputStream, PipeReader, PipeWriter
合并文件流用SequenceInputStream
遇到从Stream到Reader,Writer的转换,我们用InputStreamReader和OutputStreamWriter
InputStreamReader和OutputStreamWriter两个流在构造的时候主要可以加入字符编码方式,如:
new InputStreamReader(new FileInputStream("d:/hello.txt"), "utf-8"),
new OutputStreamWriter(new FileOutputStream("d:/hello.txt"), "utf-8")
要想加入缓冲用BufferedInputStream, BufferedOutputStream, BufferedReader, BufferedWriter
下面举例应用:
读取d盘下的Demo.java文件
FileReader fr = new FileReader("d:/Demo.java");
char[] achar = new char[1024];
int num = 0;
while (-1 != (num=fr.read(achar)))
{
System.out.println(new String(achar,0,num));
}
fr.close();
还可以这样读:
FileReader fr = new FileReader("d:/Demo.java");
int ch=0;
while(-1!=(ch=fr.read()))
{
System.out.print((char)ch);
}
fr.close();
带缓冲区的读入:
FileReader fr = new FileReader("d:/Demo.java");
BufferedReader br = new BufferedReader(fr);
String str;
while (null != (str = br.readLine()))//readLine()读一行,并不读取换行符
{
System.out.println(str);
}
br.close();
向d盘下的hello.txt文件写入字符串,并处理IO异常
FileWriter f = null;
try
{
f = new FileWriter("d:/hello.txt",true);//追加内容,并不覆盖文件
String str = "hello world welcome";
f.write(str);
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
try
{
if (f != null)
f.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
还可以一个字符一个字符写入:
String str = "hello world welcome ";
char[] buffer = new char[str.length()];
str.getChars(0, str.length(), buffer, 0);
FileWriter f = new FileWriter("d:/hello.txt");
for (int i = 0; i < buffer.length; i++)
{
f.write(buffer[i]);
}
f.close();
带缓冲区的写入:
FileWriter f = new FileWriter("d:/hello.txt", true);// 追加内容,并不覆盖文件
BufferedWriter bw = new BufferedWriter(f);
bw.write("hello");
bw.newLine();// 换行符
bw.write("world");
bw.newLine();
bw.write("comeon");
bw.close();
下面程序实现对图片文件的拷贝:
InputStream in = new FileInputStream("d:/11.jpg");
byte[] b = new byte[200];
int length = 0;
OutputStream os;
os = new FileOutputStream("d:/22.jpg");
while (-1 != (length = in.read(b)))
{
os.write(b, 0, length);
}
in.close();
os.close();
还可以带缓冲区的拷贝:
FileInputStream fis = new FileInputStream("d:/11.jpg");
BufferedInputStream br = new BufferedInputStream(fis);
byte[] buf = new byte[1024];
int length = 0;
FileOutputStream fos = new FileOutputStream("d:/22.jpg");
BufferedOutputStream os = new BufferedOutputStream(fos);
while (-1 != (length = br.read(buf)))
{
os.write(buf, 0, length);
}
br.close();
os.close();
下面是ByteArrayOutputStream的一个应用,从内存读取字符串,
存到另一个字节数组打印,也可以writeTo到OutputStream
String str = "welcome";
byte[] abyte = str.getBytes();
ByteArrayOutputStream b = new ByteArrayOutputStream();
b.write(abyte);
byte[] buf = b.toByteArray();
for (int i = 0; i < buf.length; i++)
{
System.out.print(" " + (char) buf[i]);
}
OutputStream out = new FileOutputStream("d:/hello.txt");
b.writeTo(out);
out.close();
InputStream有个方法available可以读取输入流当前可读取的字节数,
就可创建一个已知大小的字节数组,看应用:
FileInputStream fis = new FileInputStream("d:/Demo.java");
byte[] buf = new byte[fis.available()];
fis.read(buf);
System.out.println(new String(buf));
fis.close();
下面的程序实现从键盘录入,当敲回车时打印出来,录入over程序结束
InputStream in = System.in;
StringBuilder sb = new StringBuilder();
while (true)
{
int ch = in.read();
if (ch == '\r')
continue;
if (ch == '\n')
{
String s = sb.toString();
if ("over".equals(s))
break;
System.out.println(s);
sb.delete(0, sb.length());
}
else
sb.append((char) ch);
}
下面通过流的组合从键盘录入数据,打印在控制台
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
OutputStreamWriter osw = new OutputStreamWriter(System.out);
BufferedWriter bw = new BufferedWriter(osw);
String line = null;
while (null != (line = br.readLine()))
{
bw.write(line);
bw.newLine();
bw.flush();
}
br.close();
下面代码是ObjectOutputStream和ObjectInputStream的应用,写3个对象到
hello.txt文件中,然后再读取出来。
public class SerializableTest1
{
public static void main(String[] args) throws Exception
{
Person11 p1 = new Person11(20, "zhangsan", 4.55);
Person11 p2 = new Person11(50, "lisi", 4.67);
Person11 p3 = new Person11(10, "wangwu", 17.78);
FileOutputStream fos = new FileOutputStream("d:/hello.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(p1);
oos.writeObject(p2);
oos.writeObject(p3);
oos.close();
System.out.println("--------------------");
FileInputStream fis = new FileInputStream("d:/hello.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
Person11 p = null;
for (int i = 0; i < 3; i++)
{
p = (Person11) ois.readObject();
System.out.println(p.age + "," + p.name + "," + p.height);
}
ois.close();
}
}
class Person11 implements Serializable//序列化要实现Serializable接口
{
int age;
String name;
double height;
public Person11(int age, String name, double height)
{
this.age = age;
this.name = name;
this.height = height;
}
}
另外,如果序列化写入或读取对象时,想要控制对象写入的信息,
就要自己实现writeObject,readObject方法,看下面例子只写入
Person对象的name和age
public class SerializableTest2
{
public static void main(String[] args) throws Exception
{
Person2 p1 = new Person2(20, "zhangsan", 4.55);
Person2 p2 = new Person2(50, "lisi", 4.67);
Person2 p3 = new Person2(10, "wangwu", 17.78);
FileOutputStream fos = new FileOutputStream("d:/haha.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(p1);
oos.writeObject(p2);
oos.writeObject(p3);
oos.close();
System.out.println("--------------------");
FileInputStream fis = new FileInputStream("d:/haha.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
Person2 p = null;
for (int i = 0; i < 3; i++)
{
p = (Person2) ois.readObject();
System.out.println(p.age + "," + p.name + "," + p.height);
}
ois.close();
}
}
class Person2 implements Serializable
{
int age;
String name;
double height;
public Person2(int age, String name, double height)
{
this.age = age;
this.name = name;
this.height = height;
}
//提供writeObject readObject 序列化内容就要具体自己实现
private void writeObject(java.io.ObjectOutputStream out) throws IOException
{
out.writeInt(age);
out.writeUTF(name);
System.out.println("write object");
}
private void readObject(java.io.ObjectInputStream in) throws IOException,
ClassNotFoundException
{
age = in.readInt();
name = in.readUTF();
System.out.println("read object");
}
}
打印流PrintStream和PrintWriter可以将各种数据类型的数据都原样打印,
而且可以直接与文件相关联。
下面看一个PrintWriter的应用,键盘录入内容,打印到hello.txt文件中,
PrintWriter追加true表示自动刷新。
注意如果直接 new PrintWriter("d:/hello.txt"),不会自动刷新,
把文件封装到流里才会自动刷新。
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
String str = null;
//PrintWriter pw = new PrintWriter(System.out, true);//true,自动刷新
//PrintWriter pw = new PrintWriter("d:/hello.txt");
PrintWriter pw = new PrintWriter(new FileWriter("d:/hello.txt"),true);
while (null != (str = br.readLine()))
{
if("over".equals(str))
break;
pw.println(str);//println刷新
}
br.close();
pw.close();
看下面的代码可以将数组异常信息输出到log.txt文件中:
try
{
int[] a = new int[] { 2, 4, 5 };
System.out.println(a[5]);
}
catch (Exception e)
{
e.printStackTrace(new PrintStream(new FileOutputStream("d:/log.txt")));
}
下面的代码可以将系统的属性信息打印到d盘的properties文件中
Properties p = System.getProperties();
p.list(new PrintStream("d:/properties.txt"));
下面看一下SequenceInputStream流的应用,它可以将多个文件内容
一起合并读入到另一个文件中。
Vector
v.add(new FileInputStream("d:/j1.txt"));
v.add(new FileInputStream("d:/j2.txt"));
v.add(new FileInputStream("d:/j3.txt"));
Enumeration
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("d:/j4.txt");
byte[] buf = new byte[1024];
int len = 0;
while ((len = sis.read(buf)) != -1)
{
fos.write(buf, 0, len);
}
fos.close();
sis.close();
有合并就有分割,看下面的例子可把一个文件分成任意
大的任意等份。
如果mm.mp3文件为5M,下面程序分割文件每份为2M,分成3份
FileInputStream fis = new FileInputStream("d:/mm.mp3");
FileOutputStream fos = null;
byte[] buf = new byte[1024 * 1024];
int len = 0;
int count = 1;
while (fis.available() > 0)
{
fos = new FileOutputStream("d:/www/" + (count++) + ".mp3");
int mark = 0;
while ((len = fis.read(buf)) != -1)
{
fos.write(buf, 0, len);
mark++;
if (mark == 2)
break;
}
fos.close();
}
下面谈一下字符编码的问题:
编码: 字符串变成字节数组
解码 : 字节数组变成字符串
String -- byte[] str.getBytes(charsetName);
byte[] -- String: new String(byte[],charsetName);
假如一个txt文件是按utf-8来编码的,那我们从硬盘读取该文件
的时候,也应该指定编码为utf-8,
InputStreamReader isr = new InputStreamReader(new FileInputStream("d:/as.txt"), "utf-8");
当然,我们向一个文件输出内容的时候,也可以指定编码
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d:/as.txt"), "UTF-8");
osw.write("你好啊");
我们知道流是用来操作数据的,而数据的主要体现形式就是文件,文件又包含了很多
自己的属性和行为信息。java中的File类用来将文件和文件夹封装成对象,方便对文件
和文件夹的属性信息进行操作。
File常用方法:
createNewFile() 文件已经存在,则不创建
boolean delete()
void deleteOnExit() 在程序退出时删除文件
boolean canExecute() 文件是否可以执行
boolean mkdir() 创建一级目录
boolean mkdirs() 创建多级目录
boolean exists() 文件是否存在
boolean isDirectory()
boolean isFile()
boolean isHidden() 注意一般不要拿硬盘中隐藏的文件
boolean isAbsolute()
下面是File类应用举例:
File file = new File("d:/aa.txt");//绝对路径
//File file = new File("aa.txt");//相对路径
file.createNewFile();
System.out.println(file.exists());
File file = new File("c:/444");
file.mkdir();
File file2 = new File(file, "hello.txt");
file2.createNewFile();
下面程序打印abc文件夹下所有文件和文件夹的名字
File file = new File("c:/abc");
File[] files = file.listFiles();
for (File f : files)
{
System.out.println(f.getName());
}
下面程序打印abc文件夹下后缀名为.txt文件的名字
File file = new File("C:\\abc");
String[] names = file.list(new FilenameFilter()
{
public boolean accept(File dir, String name)
{
if (name.endsWith(".txt"))
{
return true;
}
return false;
};
});
for (String name : names)
{
System.out.println(name);
}
下面程序打印abc文件夹下所有文件的扩展名字
File file = new File("d:/abc");
File[] files = file.listFiles();
for (File f : files)
{
String str = f.getName();
int lastIndex = str.lastIndexOf(".");
String exname = str.substring(lastIndex + 1);
System.out.println("文件的扩展名为:" + exname);
}
下面程序采用递归打印bb文件夹下所有文件及子文件的名字
public class Test
{
public static void showDir(File file, int level)
{
String p = " ";
for (int i = 0; i < level; i++)
{
p = p + " ";
}
File[] files = file.listFiles();
for (File f : files)
{
System.out.println(p + f.getName());
if (f.isDirectory())
showDir(f, level + 1);
}
}
public static void main(String[] args)
{
File file = new File("c:/bb");
showDir(file, 0);
}
}
下面程序采用递归删除abc文件下所有文件
public class DeleteTest
{
public static void deleteAll(File file)
{
if (file.isFile() || file.list().length == 0)
{
file.delete();
}
else
{
File[] files = file.listFiles();
for (File f : files)
{
deleteAll(f);
f.delete();
}
}
}
public static void main(String[] args)
{
deleteAll(new File("c:/abc"));
}
}
java中的IO和File都是很重要的内容,好了,关于这部分的内容
就学习和总结到这了,谢谢。