一、流概述:
流是一组有序的数据序列,根据操作的类型,可分为输入流和输出流。I/O(Input/Output)流提供了一套通道程序,可以使用这个通道吧源中的字节序列送到目的地。虽然I/O流通常和磁盘文件存取有关,但是程序的源和目的地可以是键盘,鼠标,内存或显示器窗口等。
二、输入/输出流
Java语言中定义了许多类专门负责各种方式的输入/输出,这些类都被放在java.io包中。其中,所有输入流类都是抽象类InputStream(字节输入流)或抽象类Reader(字符输入流)的子类;而所有输出流都是抽象类OutputStream(字节输出流)或抽象类Writer(字符输出流)的子类
1、输入流
InputStream类是字节输出流的抽象类,是所有字节输入流的父类。InputStream类的一些方法简要说明
read()方法:从输入流中读取数据的下个字节,返回0~255范围的int字节值。如果因为已经到达末尾而没有可用的字节则返回值-1.
read(byte[] b):从输入流读入一定长度的字节,并以整数的形式返回字节数。
mark(int readlimit)方法:在输入流的当前位置放置一个标记,readlimit参数告知此输入流在标记桅子花失效前允许读取的字节数。
reast()方法:将输入指针返回到当前所做的标记处。
skip(long n)方法:跳过输入流上的n个字节并返回实际跳过的字节数
markSupported()方法:如果当前流支持mark()/rest()操作就返回true.
close()方法:关闭输入流并释放与该流关联的所有系统资源。
并不是所有的InputStream类的子类都支持InputStream中定义的方法,如skip()、mark()、reast()等方法只对某些子类有用
2、输出流
OutputStream类是字节输出流的抽象类,此抽象类是表示输出字节流所有类的超类
OutputStream类中所有的方法均返回void,在遇到错误时会引发IOException异常,一些简单的方法如下
write(int b):将指定的字节写入此输出流
write(byte[] b):将b个字节从指定的byte数组写入此输出流
write(byte[] b, int off, int len):将指定byte数组从偏移量off开始的len个字节写入此输出流
finish()方法:彻底完成输出并清空缓存区
close()方法:关闭输出流
三、File类
File类是java.io包中唯一代表磁盘文件本身的对象。File类定义了一些与平台无关的方法来操作文件,可以通过调用File类中的方法,实现创建,删除,重命名文件等操作。File类的对象主要用来获取文件本身的一些信息,如文件所在的目录,文件的长度,文件的读写权限等。数据流可以将数据写入到文件中,文件也是数据流最常用的数据媒体
1、文件的创建和删除
创建:
I、File(String pathname)
该构造方法通过将给定路径名字字符串转换为抽象路径名来创建一个新File实例
New File(String pathname)
pathname指路径名称(包含文件名)例如:
File file = new File("d:/1.doc");
II、File(String parent, String child)
该构造方法根据定义的父路径和子路径字符串(包含文件名)创建一个新的File对象
new File(String parent, String child)
parent:父路径字符串,例如:D:/或者D:/doc
child:子路径字符串,例如:letter.txt
III、File(File f, String child)
f:父路径对象,例如:D:/doc/。
child:字路径字符串,例如:letter.text
附:对于windows平台,包含盘符的路径名前缀有驱动号和一个“:”组成。如果路径名是绝对路径名,还可以后跟”\“。
import java.io.File;
public class FileTest {
public static void main(String[] args) {
File file = new File("word.txt");
if (file.exists()) {
file.delete();
System.out.println("文件已经删除");
} else {
try {
file.createNewFile();
System.out.println("文件已经创建");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
2、获取文件信息
File类中的常用方法
import java.io.File;
public class FileTest {
public static void main(String[] args) {
File file = new File("word.txt");
if (file.exists()) {
String name = file.getName();
long length = file.length();
boolean hidden = file.isHidden();// 判断文件是否为隐藏文件
System.out.println("文件名称 " + name);
System.out.println("文件长度 " + length);
System.out.println("该文件是隐藏文件吗" + hidden);
} else {
System.out.println("文件不存在");
}
}
}
结果:
四、文件输入\输出流
程序运行期间,大部分数据都是在内存中进行操作,当程序结束或关闭时,这些数据将消失。如果需要将数据永久保存,可使用文件输入\输出流与指定的文件建立连接,将需要的数据永久保存到文件中。
1、FileInputStream与FileOutputStream类
FielInputStream类与FileOutputStream类都是用来操作磁盘文件。如果用户的文件读取需求比较简单,则可以使用FileInputStream类,该类继承InputStream类。FileOutputStream类与FileInputStream类对应,提供了基本的文件写入能力。FileOutputStream类是OutputStream的子类。
FileInputStream类常用的构造方法如下
FileInputStream(String name):使用给定的文件名name创建一个FileInputStream对像
FileInputStream(File file):使用File对象创建FileInputStream对象(该方法允许在把文件连接输入流之前对文件做进一步分析)
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class FileTest {
public static void main(String[] args) {
File file = new File("word.txt");
try {
// 创建FileOutputStream对象
FileOutputStream out = new FileOutputStream(file);
// 创建byte型数组
byte buy[] = "哈哈".getBytes();
out.write(buy);// 将数组中的信息写入到文件中
out.close();// 将流关闭
} catch (Exception e) {
e.printStackTrace();// 输出异常信息
}
try {
FileInputStream in = new FileInputStream(file);
byte byt[] = new byte[11];
int len = in.read(byt);
// 将文件中的信息输出
System.out.println("文件中的信息是:" + new String(byt, 0, len));
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
结果:
附:虽然在Java程序结束时自动关闭所有打开的流,但是使用完流之后,显式的关闭所有打开的流仍是一个好习惯
五、FileReader和FileWriter类
使用FileOutputStream类向文件中写入数据与使用FileInputStream类从文件中将内容读出来,都存在一点不足,即这两个类只提供了对字节或字节数组的读取方法。由于汉字在文件中占有两个字节,如果使用字节流,读取不好可能会出现乱码现象,此时采用字符流Reader或Writer类即可避免这种现象
FileReader和FileWriter字符流对应了FileInputStream类和FileOutputStream类。FileReader流顺序地读取文件,只要不关闭流,每次调用read()方法就顺序地读取源中其余内容,直到源的末尾或流被关闭。
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
public class Ftest extends JFrame {
private static final long serivalVersionUID = 1L;
private JPanel jContentPane = null;// 创建面板对象
private JTextArea jTextArea = null;
private JPanel controlPanel = null;
private JButton openButton = null;
private JButton closeButton = null;
private JButton getOpenButton() {
if (openButton == null) {
openButton = new JButton();
openButton.setText("写入文件");// 修改按钮的提示信息
openButton.addActionListener(new ActionListener() {
// 按钮单击事件
@Override
public void actionPerformed(ActionEvent arg0) {
// 创建文本对象
File file = new File("word.txt");
try {
// 创建FileWriter对象
FileWriter out = new FileWriter(file);
// 获取文本域中的文本
String s = jTextArea.getText();
out.write(s);
out.close();
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
}
return openButton;
}
private JButton getCloseButton() {
if (closeButton == null) {
closeButton = new JButton();
closeButton.setText("读取文件");
closeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
File file = new File("word.txt");
try {
FileReader in = new FileReader(file);
char byt[] = new char[1024];
int len = in.read(byt);
jTextArea.setText(new String(byt, 0, len));
in.close();
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
}
return closeButton;
}
public Ftest() {
super();
initialize();
}
private void initialize() {
this.setSize(300, 200);
this.setContentPane(getJContentPane());
this.setTitle("JFrame");
}
private JPanel getJContentPane() {
if (jContentPane == null) {
jContentPane = new JPanel();
jContentPane.setLayout(new BorderLayout());
jContentPane.add(getJTextArea(), BorderLayout.CENTER);
jContentPane.add(getControlPanel(), BorderLayout.SOUTH);
}
return jContentPane;
}
private Component getJTextArea() {
// TODO Auto-generated method stub
return null;
}
private Component getControlPanel() {
// TODO Auto-generated method stub
return null;
}
public static void main(String[] args) {
Ftest thisClass = new Ftest();
thisClass.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
thisClass.setVisible(true);
}
}
五、带缓存的输出/输入流
缓存是I/O的一种性能优化。缓存流为I/O流增加了内存缓存区。有了缓存区,使得流上执skip()、mark()和rest()方法都成为可能。
1、BufferedInputStream和BufferedOutPutStream类
BufferedInputStream类可以对所有InputStream类进行带缓存区的包装以达到性能的优化。BufferedInputStream类有两个构造方法:
BufferedInputStream(InputStream in)
BufferedInputStream(InputStream in, int size)
第一种形式的构造方法创建了一个带有32个字节的缓存流;第二中形式的构造方法按指定的大小来创建缓存区。一个最优的缓存区的大小,取决于它所在的操作系统、可用的内存空间以及机器配置。从构造方法可以看出,BufferedInputStream对象位于InputStream类对象之前
BufferedOutputStream同理
2、BufferReader与BufferWriter类
BufferReader类和BufferWriter类分别继承Reader类和Writer类。这两个类同样具有内部缓存机制,并可以以行为单位进行输入/输出
BufferReader常用的方法如下
read()方法:读取单个字符
readLine()方法:读取一个文本行,并将其返回为字符串,若无数据可读,则返回null。
BufferWriter类中的方法都返回void,常见的方法如下:
write(String s,int off, int len):写入字符串的某个人部分
flush()方法:刷新该流的缓存
newLine()方法: 写入一个行分隔符
在石油BufferWriter类的write()方法时,数据并没有立刻被写入至输出流,而是首先进入缓存区中,如果想立刻将缓存区的数据写入输出流,一定要调用flush()方法。
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
public class Student {
public static void main(String[] args) {
// 第一字符串数组
String content[] = { "好久不见", "最近好吗" };
File file = new File("word.txt");
try {
FileWriter fw = new FileWriter(file);
// 创建BufferWriter
BufferedWriter bufw = new BufferedWriter(fw);
for (int k = 0; k < content.length; k++) {
bufw.write(content[k]);
bufw.newLine();
}
bufw.close();
fw.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
FileReader fr = new FileReader(file);
BufferedReader bufr = new BufferedReader(fr);
String s = null;
while ((s = bufr.readLine()) != null) {
System.out.println(" " + s);
}
bufr.close();
fr.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
结果:
六、数据输入输出流
数据输入输出流(DataInputStream类与DataOutputStream类)允许应用程序以与机器无关的方式从底层输入流中读取基本的Java数据类型。也就是说,当读取一个数据的时候,不必再关心这个数值应当是哪个字节
DataInputStream类与DataOutputStream类的构造方法如下:
DataInputStream(InputStream in):使用指定的基础InputStream创建一个DataInputStream。
DataOutputStream(OutputStream out):创建一个新的数据输出流,将数据写入带指定的基础流。
DataOutputStream类提供了如下3种写入字符串的方法
writeBytes(String s)。
writeChars(String s)。
writeUTF(String s)。
由于Java中的字符是Unicode编码,是双字节的,writeBytes只是将字符串的每一个字符的低字节内容写入到目标设备中,而writeChars将字符串的每一个字符的两个字节的内容都写到目标设备中;writeUTF将字符串按照UTF编码后的字节长度写入目标设备,然后才是每一个字节的UTF编码。
DataInputStream类只提供一个readUTF()方法返回字符串,这是因为要在一个连续的字节流读取一个字符串,如果没有特殊的标记作为一个字符串的结尾,并且不知道这个字符串的长度,就无法知道读取到什么位置才是这个字符串的结束。DataOutputStream类中只有writeUTF()方法向目标设备中写入字符串的长度,所以也能准确的读回写入字符串
七、zip压缩输入/输出流
在Java中使用java.util.zip包这种的ZipOutputStream类和ZipInputStream类来实现文件的压缩和解压缩。
1、压缩文件
ZipOutputStream类将文件压缩为.zip文件。ZipOutputStream类的构造方法
ZipOutputStream(OutputStream out);
常用的方法
putNextEntry(ZipEntry e):开始写一个新的ZipEntry,并将流内的位置移至此entry所指数据的开头
write(byte[] b, int off, int len):将字节数组写入当前ZIP条目数据
finish():完成写入ZIP输出流的内容,无须关闭它所配合的OutputStream
setComment(String comment):可设置此ZIP文件的注释文字
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class MyZip {
private void zip(String zipFileName, File inputFile) throws Exception {
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(
zipFileName));
zip(out, inputFile, "");
System.out.println("压缩");
out.close();
}
private void zip(ZipOutputStream out, File f, String s) throws Exception {
if(f.isDirectory()){
File[] fl = f.listFiles();
out.putNextEntry(new ZipEntry(s + "/"));
s = s.length()==0?"":s+"/";
for(int i = 0;i<fl.length;i++){
zip(out,fl[i],s+fl[i]);
}
}
else{
out.putNextEntry(new ZipEntry(s));
FileInputStream in = new FileInputStream(f);
int b;
System.out.println(s);
while((b = in.read())!=-1){
out.write(b);
}
in.close();
}
}
public static void main(String[] args) {
MyZip book = new MyZip();
try {
book.zip("E:/hello.zip", new File("E:/hello"));
System.out.println("压缩完成");
} catch (Exception e) {
}
}
}
结果:
2、解压缩文件
ZipInputStream类可读取ZIP压缩格式的文件,包括已压缩和未压缩的条目(entry)。ZipInputStream类的构造方法:
ZipInputStream(InputStream in)
常用的方法:
read(byte[] b, int off, int len):读取目标b数组内off偏移量的长度,长度是len字节
available:判断是否已读完目前entry所指定的数据。已读完返回0,否则返回1.
closeEntry():关闭当前ZIP条目并定位流以读取下一个条目
skip(long b):跳过当前ZIP条目中指定的字节数
getNextEntry():读取下一个ZipEntry,并将流内的位置移置该entry所指数据的开头
createZipEntry(String name):以指定的name参数新建一个zipEntry 对象
import java.io.File;
import java.io.FileInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class Decompressing {
public static void main(String[] args) {
ZipInputStream zin;
try {
zin = new ZipInputStream(new FileInputStream("hello.zip"));
ZipEntry entry = zin.getNextEntry();
while (((entry = zin.getNextEntry()) != null)
&& !entry.isDirectory()) {
File file = new File("d:\\" + entry.getName());
System.out.println(file);
if (!file.exists()) {
file.mkdirs();
file.createNewFile();
}
zin.closeEntry();
System.out.println(entry.getName() + "解压成功");
}
zin.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}