Java的IO及路径问题
1.流的类型
根据流动方向的不同,流分为输入流和输出流;
对于输入和输出流,由于传输格式的不同,又分为字节流和字符流:
字节流是指8位的通用字节流,以字节为基本单位,在java.io包中,对于字节流进行操作的类大部分继承于InputStream(输入字节流)类和OutputStream(输出字节流)类;常用于读二进制文件,如图片、声音、影像等文件。
字符流是指16位的Unicode字符流,以字符(两个字节)为基本单位,非常适合处理字符串和文本,对于字符流进行操作的类大部分继承于Reader(读取流)类和Writer(写入流)类;以字符为单位读取文件,常用于读文本,数字等类型的文件
常用流的结构:
读:
InputStream: FileInputStream : BufferedInputStream
ObjectInputStream
Reader:InputStreamReader :FileReader
BufferedReader :LineNumerReader
写:input-->output,Reader-->Writer
2.学习I/O明白java里的路径很重要:
默认路径:Myeclipse里的默认路径为工程的根目录(即src的上一层目录,与src文件夹在同一目录下)
绝对路径:使用/ 或 \\开头的从根目录出发路径。因为/代表根目录在java中\\与/起同样作用。
相对路径:
1.基于默认路径(即工程)的相对路径 "src/com/lavasoft/res/a.txt"
2.基于该类的相对路径
URL uri = className.class.getResource("/com/lavasoft/res/a.txt"); 这里的 / 表示src根目录
如果用来读取文件,我们还可以使用FileInputStream和FielReader在讲文件的读写前,我们先要了解File类:
File的创建:
public class FileTest {
public static void main(String[] args) {
File file = new File("text.txt"); //创建文件对象
if(file.exists()){
file.delete(); //如果文件存在则删除
}else{
try {
file.createNewFile(); //如果不存在则创建
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
对文件的读取:
过程:将file变成Stream再将Stream变成String
FileInputStream类:
FileInputStream类称为文件输入流,继承于InputStream类,是进行文件读操作的最基本类;
它的作用是将文件中的数据输入到内存中,我们可以利用它来读文件;
由于它属于字节流,因此在读取Unicode字符(如中文)的文件时可能会出现问题。
public class FileInputStreamDemo1 {
public static void main(String[] args) {
try {
File file = new File("test.txt"); //创建文件对象
//使用文件对象创建文件输入流对象,相当于打开文件
FileInputStream fis = new FileInputStream(file);
for (int i = 0; i < file.length(); i++) {
char ch = (char)(fis.read()); //循环读取字符
System.out.print(ch);
}
System.out.println();
fis.close(); //关闭流
} catch (FileNotFoundException fnfe) {
System.out.println("文件打开失败。");
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
//与上面不同这个确定了一次性读取多少个字节存入字节数组中,在从数组中循环取出,数组相当于一个缓冲,提高了效率。
public class FileInputStreamDemo2 {
public static void main(String[] args) {
try {
File file = new File("test.txt"); //创建文件对象
FileInputStream fis = new FileInputStream(file);
//根据文件的字节长度创建字节数组,一次性读完
byte[] buf = new byte[(int)(file.length())];
fis.read(buf); //读取文件中的数据存放到字节数组中
String str = new String(buf); //利用字节数组创建字符串
System.out.println(str); //打印字符串
fis.close(); //关闭流
} catch (FileNotFoundException fnfe) {
System.out.println("文件打开失败。");
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
//同理,文件输出流
FileOutputStream类:
FileOutputStream类称为文件输出流,继承于OutputStream类,是进行文件写操作的最基本类;
它的作用是将内存中的数据输出到文件中,我们可以利用它来写文件。
public class FileOutputStreamDemo1
{
//在函数内部不进行异常处理,将异常抛出函数外部
public static void main(String[] args) throws IOException
{
String str = "Hello world!";
File file = new File("test.txt"); //创建文件对象
//通过文件对象创建文件输出流对象
//附加第二个参数true,指定进行文件追加,默认为不追加。也可使用RandomAccessFile来进行追加,该类可一调用seek找到最后一个字符位置,再进行写入,所以该类还可以用来做随机读取(读取位置可设定)。
FileOutputStream fos = new FileOutputStream(file, true);
//逐个将字节逐个写入到文件中
for (int i = 0; i < str.length(); i++)
{
fos.write(str.charAt(i));
}
fos.close(); //关闭流
}
}
public class FileOutputStreamDemo2
{
//在函数内部不进行异常处理,将异常抛出函数外部
public static void main(String[] args) throws Exception
{
String str = "I Love Java";
//通过文件名创建文件输出流对象
FileOutputStream fos = new FileOutputStream("test.txt");
//将字符串转化为字节数组
byte[] buffer = str.getBytes();
//将字节数组中包含的数据一次性写入到文件中
fos.write(buffer);
//关闭流
fos.close();
}
}
FileInputStream/FileOutputStream小结:
FileInputStream类和FileOutputStream类是成对出现的,一个进行输入(读文件)操作,一个进行输出(写文件)操作;
由于采用字节方式进行数据传输,不必考虑数据的格式问题,这两个类对文件操作的效率较高;
可以使用这两个类完成复制文件的操作。
public class CopyFileDemo {
public static void main(String[] args) throws IOException {
File srcFile = new File("src.dat"); //源文件对象
File destFile = new File("dest.dat"); //目标文件对象
if (!(destFile.exists())) { //判断目标文件是否存在
destFile.createNewFile(); //如果不存在则创建新文件
}
//使用源文件对象创建文件输入流对象
FileInputStream fis = new FileInputStream(srcFile);
//使用目标文件对象创建文件输出流对象
FileOutputStream fos = new FileOutputStream(destFile);
byte[] buf = new byte[1024]; //创建字节数组,作为临时缓冲
System.out.println("开始复制文件...");
while (fis.read(buf) != -1) { //循环从文件输入流中读取数据到数组
fos.write(buf); //从数组中写入到文件输出流中
}
System.out.println("文件复制成功!");
fis.close(); //关闭流
fos.close();
}
}
字符流:
FileInputStram类和FileOutputStream类虽然可以高效率地读/写文件,但对于Unicode编码的文件,使用它们有可能出现乱码;
考虑到Java是跨平台的语言,要经常操作Unicode编码的文件,使用字符流操作文件是有必要的,且字符类型可以用new inputStreamReader(InputStream in,String charset )将字节流转换为GBK等字符格式;
使用字符流将涉及到以下4个类:(Reder和Writer的子类)
FileReader类和FileWriter类;
BufferedReader类和BufferedWriter类。
FileReader类:
FileReader类称为文件读取流,允许以字符流的形式对文件进行读操作,其构造方法有3种重载方式,以下是常用的几种:
该类将从文件中逐个地读取字符,效率比较低下,可以一次读取多个字符,采用char数组做缓冲(类似于上面一次读取多个字节的代码)。
FileReader配合BufferedReader读文件示例:将FileReader包装到BufferedReader可以一次读一行,常用于读面向行的格式化文件
public class RraderDemo
{
public static void main(String[] args) throws IOException
{
File file = new File("test.txt");
//通过文件对象创建文件读取流对象
FileReader fr = new FileReader(file);
//将文件读取流包装成缓冲读取流
BufferedReader br = new BufferedReader(fr);
String str;
while ((str = br.readLine()) != null) //逐行读取数据
{
System.out.println(str);
}
br.close(); //关闭流
fr.close(); //关闭流
}
}
//同理利用FileWriter和BufferedWriter可以写如数据