显然,这是两种“字节流”,FileInputStream是“文件字节输入流”,FileOutputStream是“文件字节输出流”
public class FileInputStreamTest {
public static void main (String[] args) {
//创建文件字节输入流
FileInputStream fis = new FileInputStream ("文件路径(相对或绝对路径)");
/*
FileInputStream类的构造方法可以传入一个File类引用或文件的路径
这里在创建fis时,会抛出一个FileNotFoundException
所以需要把这句话放进try catch中或在main方法一开始就throws掉
*/
}
}
修改后的代码如下:
public class FileInputStreamTest {
public static void main (String[] args) {
//创建文件字节输入流
FileInputStream fis;
/*
FileInputStream类的构造方法可以传入一个File类引用或文件的路径
这里在创建fis时,会抛出一个FileNotFoundException
所以需要把这句话放进try catch中或在main方法一开始就throws掉
*/
try
{
fis = new FileInputStream ("文件路径(相对或绝对路径)");
}
catch (FileNotFoundException e)
{
e.printStackTrack ();
}
}
}
接下来就要读文件
首先准备好一个文件,在里面存入“abcdef”
利用FileInputStream类中的read方法读取数据,会返回一个int类型的数据
public class FileInputStreamTest {
public static void main (String[] args) {
//创建文件字节输入流
FileInputStream fis = null;
/*
FileInputStream类的构造方法可以传入一个File类引用或文件的路径
这里在创建fis时,会抛出一个FileNotFoundException
所以需要把这句话放进try catch中或在main方法一开始就throws掉
*/
try {
fis = new FileInputStream ("文件路径(相对或绝对路径)");
//读
int i1 = fis.read (); //97
int i2 = fis.read (); //98
int i3 = fis.read (); //99
int i4 = fis.read (); //100
int i5 = fis.read (); //101
int i6 = fis.read (); //102
int i7 = fis.read (); //-1
System.out.println (i1);
System.out.println (i2);
System.out.println (i3);
System.out.println (i4);
System.out.println (i5);
System.out.println (i6);
System.out.println (i7);
} catch (FileNotFoundException e) {
e.printStackTrace ();
} catch (IOException e) {
e.printStackTrace ();
} finally {
try {
fis.close ();
} catch (IOException e) {
e.printStackTrace;
}
}
}
}
因为read方法会抛出一个IOException,所以将这个异常捕获
read方法一次只读一个字节,英文字母刚好就是一个字节,而a对应的ASCII码是97,所以read返回了97~102的数字。
当文件被读取完时,read方法会返回-1,所以最后的i7是-1
每个流在用完之后都应该关闭,即执行fis.close ()方法,但是close方法会抛出一个IOException异常,故需要捕获。
虽然上面的程序可以将文件读完,但是需要提前知道文件的大小,所以利用文件读完后read方法返回-1,引入循环,代码如下:
public class FileInputStreamTest {
public static void main (String[] args) {
//创建文件字节输入流
FileInputStream fis = null;
try {
fis = new FileInputStream ("文件路径(相对或绝对路径)");
//先将这种循环方法看懂,就更容易理解下面的循环
/*while (true) {
int temp = fis.read ();
if (temp == -1) {
break;
}
System.out.println (temp);
}*/
int temp = 0; // 设置temp,记录每次读取文件的返回值,若未读完,则不会返回-1,反之则返回-1
while ((temp = fis.read ()) != -1) {
System.out.println (temp);
}
} catch (FileNotFoundException e) {
e.printStackTrack ();
} finally {
try {
fis.close ();
} catch (IOException e) {
e.printStackTrace;
}
}
}
}
这种方法虽然可以循环读取,但是一次只读一个字节,效率实在是低,而且不停地像硬盘进行读操作也很伤硬盘。
于是又有了下面的操作:
public class FileInputStreamTest {
public static void main (String[] args) {
//创建文件字节输入流
FileInputStream fis = null;
try {
fis = new FileInputStream ("文件路径(相对或绝对路径)");
//准备一个byte数组
byte[] bytes = new byte[3]; // 每次只读3个字节
int i1 = fis.read (bytes); // 该方法与read()无参数方法不同,返回的是读取到的字节数,无参数read()方法返回的是读取到的字节的ASCII码
System.out.println (new String (bytes)); // 将读取到的byte数组转换为String类型,是abc
int i2 = fis.read (bytes); // 3
System.out.println (new String (bytes)); // def
int i3 = fis.read (bytes); // 1
System.out.println (new String (bytes)); // gef
int i3 = fis.read (bytes); // -1,与无参数的read()方法类似,当文件读取完后,该方法也会返回-1,后面也可以此来进行循环读取的判断条件
System.out.println (new String (bytes)); // gef,文件中存储的是abcdefg,每次读三个字节,最后以此只剩下f,read在读取时并不会清空数组再读取,而是直接进行覆盖,所以得到的是gef
} catch (FileNotFoundException e) {
e.printStackTrack ();
} finally {
try {
fis.close ();
} catch (IOException e) {
e.printStackTrace;
}
}
}
}
这样就解决了效率低的问题,因为一次读取的文件大小,取决于byte数组的大小
下面代码完成循环读取:
public class FileInputStreamTest {
public static void main (String[] args) {
//创建文件字节输入流
FileInputStream fis = null;
try {
fis = new FileInputStream ("文件路径(相对或绝对路径)");
//准备一个byte数组
byte[] bytes = new byte[3]; // 每次只读3个字节
int temp = 0;
while ((temp = fis.read (bytes)) != -1) {
System.out.print (new String (bytes, 0, temp);
}
} catch (FileNotFoundException e) {
e.printStackTrack ();
} finally {
try {
fis.close ();
} catch (IOException e) {
e.printStackTrace;
}
}
}
}
其中打印部分的代码,并不需要每次都打印byte数组的所有数据,就像上面的例子,最后以此只读取了一个g,如果全都打印的话,就会打出gef,显然是不合适的,所以调用String中带有偏移量参数和长度的构造方法,从下标为0的对象开始,打印读取到的字节数即temp个对象。
FileOutputStream与FileInputStream完全类似,只是FileOutputStream用的是write方法,且需要在关闭前调用flush方法,进行刷新,把流中剩余的字节强制写出来。
下面的代码是利用FileInputStream和FileOutputStream进行文件复制:
public class CopyTest {
public static void main (String[] args) throws Exception {
//创建流
FileInputStream fis = new FileInputStream (原文件地址);
FileOutputStream fos = new FileOutputStream (新文件地址);
//边读边写
byte[] bytes = new byte[1024]; // 每次读取1kb
int temp = 0;
whil ((temp = fis.read (bytes)) != -1) {
fos.write (bytes, 0, temp);
}
//刷新
fos.flush ();
//关闭流
fos.close ();
fis.close ();
}
}
这里为了方便看清逻辑关系,我在一开始就把异常抛出了,大家不要效仿。