1.Collection
集合框架:
Collection接口:单列集合,用来存储一个的对象
1.list接口: 有序,可重复的数据, --->"动态 " 数组
ArrayList:作为List的主要实现类,线程不安全的,效率高,底层用Object[] elementData存储
LinkList:对于频繁的插入删除操作,使用linkliist比arraylsit效率高,底层使用双向列表存储
Vector:作为List接口的古老实现类;线程安全,效率低;底层使用Object []存储
面试题:ArrayList,LinkedList,Vector三者的异同?
同:三个类都实现了list接口,存储特点相同:存储有效,可重复的数据。
不同:见上
2. set接口: 无序,不可重复 --------> 集合
HashSet,LinkedSet,TreeSet
Map接口 :双列集合 (key,value) 存储一对数据 --> 函数
HashMap,linkedHashMap,TreeMap,Hashtable,Properies
集合Collection 存储的数据如果是自定义的对象,需要自定义(重写)类的那些方法?为什么?
equals()方法:因为List和set都需要重写这个方法
List:equals()方法
Set: (HashSet、linkedSet为例) equals()、hashCode()
(TreeSet为例) Comparable:CompareTo(Object obj)
Comparator:compare(Object o1,Object o2)
集合接口
集合框架定义了一些接口。本节提供了每个接口的概述:
序号 | 接口描述 |
---|---|
1 | Collection 接口 Collection 是最基本的集合接口,一个 Collection 代表一组 Object,即 Collection 的元素, Java不提供直接继承自Collection的类,只提供继承于的子接口(如List和set)。Collection 接口存储一组不唯一,无序的对象。 |
2 | List 接口 List接口是一个有序的 Collection,使用此接口能够精确的控制每个元素插入的位置,能够通过索引(元素在List中位置,类似于数组的下标)来访问List中的元素,第一个元素的索引为 0,而且允许有相同的元素。List 接口存储一组不唯一,有序(插入顺序)的对象。 |
3 | Set Set 具有与 Collection 完全一样的接口,只是行为上不同,Set 不保存重复的元素。Set 接口存储一组唯一,无序的对象。 |
4 | SortedSet 继承于Set保存有序的集合。 |
5 | Map Map 接口存储一组键值对象,提供key(键)到value(值)的映射。 |
6 | Map.Entry 描述在一个Map中的一个元素(键/值对)。是一个 Map 的内部接口。 |
7 | SortedMap 继承于 Map,使 Key 保持在升序排列。 |
8 | Enumeration 这是一个传统的接口和定义的方法,通过它可以枚举(一次获得一个)对象集合中的元素。这个传统接口已被迭代器取代。 |
Set和List的区别
- \1. Set 接口实例存储的是无序的,不重复的数据。List 接口实例存储的是有序的,可以重复的元素。
- \2. Set检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变 <实现类有HashSet,TreeSet>。
- \3. List和数组类似,可以动态增长,根据实际存储的数据的长度自动增长List的长度。查找元素效率高,插入删除效率低,因为会引起其他元素位置改变 <实现类有ArrayList,LinkedList,Vector> 。
2.List
三者异同
面试题:ArrayList,LinkedList,Vector三者的异同?
1.list接口: 有序,可重复的数据, --->"动态 " 数组
ArrayList:作为List的主要实现类,线程不安全的,效率高,底层用Object[] elementData存储
LinkList:对于频繁的插入删除操作,使用linkliist比arraylsit效率高,底层使用双向列表存储
Vector:作为List接口的古老实现类;线程安全,效率低;底层使用Object []存储
面试题:ArrayList,LinkedList,Vector三者的异同?
同:三个类都实现了list接口,存储特点相同:存储有效,可重复的数据。
不同:见上
ArrayList
ArrayList 源码解析
2.ArrayList源码解析
2.1 jdk7 情况下
ArrayList list = new Arraylist();//底层创建了长度为10的Object [] ElementData数组
list.add(123);//element[0] = new Integer(123)
...
list.add(2324);//如果此次添加元素导致底层elementData数组位置不够,则扩容,
默认扩容为原来的1.5倍,即创建1.5的数组,同时把原来数组元素复制到新数组中
结论:建议开发中使用带参的构造器 :ArrayList list = new Arraylist(int capacity);
2.2 jdk 8 情况下:
ArrayList list = new Arraylist();//底层elementData初始化为{},并没有创建长度
list.add(123);//第一次调用add时,底层才创建长度10的数组,并将数据123添加到数组中
...
list.add(2324);//后续与jdk 7情况一致
2.3 小结:jdk7 中的arraylist的对象创建类似于单列的饿汉式,jdk8 中的ArrayList类似于懒汉式,
延迟数组的创建,节省内存
ArrayList 方法
Java ArrayList 常用方法列表如下:
方法 | 描述 |
---|---|
add() | 将元素插入到指定位置的 arraylist 中 |
addAll() | 添加集合中的所有元素到 arraylist 中 |
clear() | 删除 arraylist 中的所有元素 |
clone() | 复制一份 arraylist |
contains() | 判断元素是否在 arraylist |
get() | 通过索引值获取 arraylist 中的元素 |
indexOf() | 返回 arraylist 中元素的索引值 |
removeAll() | 删除存在于指定集合中的 arraylist 里的所有元素 |
remove() | 删除 arraylist 里的单个元素 |
size() | 返回 arraylist 里元素数量 |
isEmpty() | 判断 arraylist 是否为空 |
subList() | 截取部分 arraylist 的元素 |
set() | 替换 arraylist 中指定索引的元素 |
sort() | 对 arraylist 元素进行排序 |
toArray() | 将 arraylist 转换为数组 |
toString() | 将 arraylist 转换为字符串 |
ensureCapacity() | 设置指定容量大小的 arraylist |
lastIndexOf() | 返回指定元素在 arraylist 中最后一次出现的位置 |
retainAll() | 保留 arraylist 中在指定集合中也存在的那些元素 //获取两个集合交集 |
containsAll() | 查看 arraylist 是否包含指定集合中的所有元素 |
trimToSize() | 将 arraylist 中的容量调整为数组中的元素个数 |
removeRange() | 删除 arraylist 中指定索引之间存在的元素 |
replaceAll() | 将给定的操作内容替换掉数组中每一个元素 //清除交集,留下不一样的 |
removeIf() | 删除所有满足特定条件的 arraylist 元素 |
forEach() | 遍历 arraylist 中每一个元素并执行特定操作 |
hashCode() | 返回当前对象哈希值 |
equals( arr ) | 判断两个arraylist是否相同 |
集合 <—>数组
//equals
System.out.println(c2.equals(c));//true
//集合 ----> 数组
Object[] array = coll.toArray();
for (int i = 0; i < array.length; i++) {
System.out.println("array[i] = " + array[i]);
}
//数组 ----> 集合 :调用Arrays类的静态方法 asList()
List<Integer> list = Arrays.asList(new Integer[]{1, 2, 3, 45, 5});
System.out.println("list = " + list);//list = [1, 2, 3, 45, 5]
//类型为int基本类型,new int[]{1, 2, 3, 45, 5}为默认为一个元素,
List list2 = Arrays.asList(new int[]{1, 2, 3, 45, 5});
System.out.println("list2.size() = " + list2.size());//1
//
List list3 = Arrays.asList(1, 2, 3, 45, 5);
System.out.println("list3.size() = " + list3.size());//list3.size() = 5
面试题
考remove() 的使用和对ArrayList底层源码的理解
@Test
public void test2() {
List list = new ArrayList();
list.add(1);//底层添加了new Integer(1)
list.add(2);
list.add(3);
update(list);
System.out.println(list);//问:输出什么? [1, 2]
}
public void update(List list) {
list.remove(2);//索引
list.remove(new Integer(2));//2 Integer对象
}
linkedList
源码解析:
3.set
接口框架
1.Set接口的框架:
|---Collection接口;单例集合,用来存储一个个对象
|---Set接口:存储无序的,不可重复的数据 。 ==>集合
|----HashSet:作为set接口的主要实现类:线程不安全的,可以存储null值
|---linkedHashSet:作为HashSet的子类,遍历且内部数据时,可以按照添加的顺序输出
对于频繁的遍历操作,LinkedHashSet效率更高
|---TreeSet: 可以按照添加对象的指定属性,进行排序。
HashSet
/*
要求:想set中添加数据,所在的类一定要重新hashcode()和equals()
重写两个方法尽可能保持一致性,:相同的对象必须具有相同的散列码
*/
@Test
public void test01() {
Set set = new HashSet<>();
set.add(1);
set.add(2);
set.add(new Person("zy", 21));
set.add(new Person("zy", 21));
set.add(1);
System.out.println(set);
}
LinkedHashSet
/*
LinkedHashSet的使用
作为HashSet的子类,在添加数据的时候,每个数据安徽维护了两个引用:pre & next,记录此数据的上一个和下一个数据
优点:对于频繁的遍历操作,LinkedHashSet效率更高
*/
@Test
public void test02() {
Set set = new LinkedHashSet<>();
set.add(1);
set.add(2);
set.add(new Person("zy", 21));
set.add(new Person("zy", 21));
set.add(1);
Iterator it = set.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
面试题??
package java_gaoji.set;
import java.util.HashSet;
import java.util.Set;
public class Test2 {
public static void main(String[] args) {
Set set = new HashSet<>();
Person p1 = new Person("aa", 1001);
Person p2 = new Person("bb", 1002);
set.add(p1);
set.add(p2);
System.out.println(set);
p1.setAge(1003);
set.remove(p1);
System.out.println(set);
set.add(new Person("aa", 1003));
System.out.println(set);
set.add(new Person("aa", 1001));
System.out.println(set);
}
}
4.Map
接口框架
|----Map:双列数据,存储key-value对的数据,
* |----HashMap:作为Map的主要实现类,线程不安全的,效率高;可以存储null的key和value
* |----LinkedHashMap:保证在遍历时可以按照添加的顺序实现遍历
* 原因:底层添加了pre和next指针
* |----TreeMap:保证按照key-value进行排序,实现排序遍历,此时考虑key的自然排序和定制排序
* 底层使用红黑书
* |----Hashtable:作为古老的实现类,线程安全的,效率低:不能存储null的key和value
* |----Properties:常用来配置文件。Key和value都是String类型
Map结构的理解
二、Map结构的理解
Key:无序、不可重复,使用Set存储所有的key。 ---> key所在的类需要重新equals()和hashCode()
value: 无序,可重复。使用Collection存储所有的value --->value需要存储所有的equals()
一个键值对:key-value构成一个Entry对象
entry:无序,不可重复。使用Set存储。
Map的迭代
可以使用 for-each 来迭代 HashMap 中的元素。
如果你只想获取 key,可以使用 keySet() 方法,然后可以通过 get(key) 获取对应的 value,如果你只想获取 value,可以使用 values() 方法。
// 引入 HashMap 类
import java.util.HashMap;
public class RunoobTest {
public static void main(String[] args) {
// 创建 HashMap 对象 Sites
HashMap<Integer, String> Sites = new HashMap<Integer, String>();
// 添加键值对
Sites.put(1, "Google");
Sites.put(2, "Runoob");
Sites.put(3, "Taobao");
Sites.put(4, "Zhihu");
// 输出 key 和 value
for (Integer i : Sites.keySet()) {
System.out.println("key: " + i + " value: " + Sites.get(i));
}
// 返回所有 value 值
for(String value: Sites.values()) {
// 输出每一个value
System.out.print(value + ", ");
}
}
}
HashMap
1.底层原理
三、HashMap底层实现原理?以jdk7 为例
HashMap hm = new HashMap();
在实例化以后,底层创建了一个长度为16 的一维数组Entry[] table
......可能执行了多次put
hm.put(key1,value);
首先,调用key1所在类的hashCode()计算key1哈希值,此哈希值经过某种计算以后,得到在Entry数组中的存储位置
如果此位置上的数据为空,此时key1-value添加成功 --情况1
如果此位置的数据不为空,(意味着此位置存在一个或者多个数据(以链表形式存在)),
比较key和已经存在的一个或者多个数据的哈希值:
如果key1的哈希值与已经存在的数据的哈希值都不相同,此时key1-value添加成功 --情况2
如果key1的哈希值和已经存在的某一个数据的哈希值相同,继续对比:调用key1所在类的equals(key1)
如果equals()返回false,此时key1-value添加成功 --情况3
如果equals() 返回true,使用value1替换value2
补充:关于情况2 和情况3:此时key-value和原来的数据以链表的形式存储
在不断添加数据的过程中,会涉及到扩容,初始长度为16,超出扩容为原来的两倍,并把原来数据复制过去
jdk8相较于jdk7 在底层实现方面的不同。
1.new HashMap():底层没有创建一个长度为16的数组
2.jdk8底层的数组是:Node[] 而非Entry []
3.首次调用put()方法时,底层创建长度16的数组
4.jdk7底层结构只有:数组+链表。
jdk8底层结构:数组+链表+红黑树
当数组的某一个索引位置上的元素以链表的形式存在的数据个数 > 8 且当前数组长度 > 64
此时索引位置上的 所有数组改为红黑树存储(提高查找效率)
TreeMap
被我跳过了
Hashtable
Properties
jdbc.properties存放在根目录下,且文件参数都属于字符串
name=dhl
password=333
package java_gaoji.MapTest;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;
public class PropertiesTest {
public static void main(String[] args) throws IOException {
Properties pros = new Properties();
FileInputStream fis = new FileInputStream("jdbc.properties");
pros.load(fis);//加载流对应的文件
String name = pros.getProperty("name");
String password = pros.getProperty("password");
System.out.println("name = " + name);
System.out.println("password = " + password);
}
}
5.Iterator
迭代器 it 的两个基本操作是 next 、hasNext 和 remove。
调用 it.next() 会返回迭代器的下一个元素,并且更新迭代器的状态。
调用 it.hasNext() 用于检测集合中是否还有元素。
调用 it.remove() 将迭代器返回的元素删除。
Iterator 类位于 java.util 包中,使用前需要引入它,语法格式如下:
import java.util.Iterator; // 引入 Iterator 类
获取一个迭代器
集合想获取一个迭代器可以使用 iterator() 方法:
// 引入 ArrayList 和 Iterator 类
import java.util.ArrayList;
import java.util.Iterator;
public class RunoobTest {
public static void main(String[] args) {
// 创建集合
ArrayList<String> sites = new ArrayList<String>();
sites.add("Google");
sites.add("Runoob");
sites.add("Taobao");
sites.add("Zhihu");
// 获取迭代器
Iterator<String> it = sites.iterator();
// 输出集合中的第一个元素
System.out.println(it.next());
}
}
执行以上代码,输出结果如下:
Google
遍历
让迭代器 it 逐个返回集合中所有元素最简单的方法是使用 while 循环:
while(it.hasNext()) {
System.out.println(it.next());
}
错误方式
//错误方式一:会各一个输出一个,最后空指针
Iterator<String> it2 = sites.iterator();
while (it2.next() != null) {
System.out.println("it2.next() = " + it2.next());
}
//错误方式二:sites.iterator().hasNext() 每次都会新建迭代器,输出的永远是第一个元素
while (sites.iterator().hasNext()) {
System.out.println(sites.iterator().next());
}
用增强for循环遍历
public static void main(String[] args) {
// 创建集合
Collection sites = new ArrayList<>();
sites.add("Google");
sites.add("Runoob");
sites.add("Taobao");
sites.add("Zhihu");
sites.add(new Person("zy", 21));
//for(集合元素的类型 局部变量 : 集合对象)
//内部仍然调用了迭代器
for (Object obj : sites) {
System.out.println("obj = " + obj);
}
}
增强for的使用原理
@Test
public void test1(){
String[] arr = new String[]{"zy", "zy", "zy"};
//方式一:普通for循环
for (int i = 0; i < arr.length; i++) {
arr[i] = "hl";
}
//方式二:增强for循环
//循环之后原来数组arr的值不会改变,arr[i] 赋值给str,修改的是str,arr[i]不变
for (String str : arr) {
str = "hl";
}
for (int i = 0; i < arr.length; i++) {
System.out.println("arr[i] = " + arr[i]);
}
}
删除元素
要删除集合中的元素可以使用 remove() 方法。
以下实例我们删除集合中小于 10 的元素:
实例
// 引入 ArrayList 和 Iterator 类
import java.util.ArrayList;
import java.util.Iterator;
public class RunoobTest {
public static void main(String[] args) {
ArrayList<Integer> numbers = new ArrayList<Integer>();
numbers.add(12);
numbers.add(8);
numbers.add(2);
numbers.add(23);
Iterator<Integer> it = numbers.iterator();
while(it.hasNext()) {
Integer i = it.next();
if(i < 10) {
it.remove(); // 删除小于 10 的元素
}
}
System.out.println(numbers);
}
}
执行以上代码,输出结果如下:
[12, 23]
6.泛型
Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
假定我们有这样一个需求:写一个排序方法,能够对整型数组、字符串数组甚至其他任何类型的数组进行排序,该如何实现?
答案是可以使用 Java 泛型。
使用 Java 泛型的概念,我们可以写一个泛型方法来对一个对象数组排序。然后,调用该泛型方法来对整型数组、浮点数数组、字符串数组等进行排序。
泛型方法
你可以写一个泛型方法,该方法在调用时可以接收不同类型的参数。根据传递给泛型方法的参数类型,编译器适当地处理每一个方法调用。
下面是定义泛型方法的规则:
- 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前(在下面例子中的 )。
- 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
- 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
- 泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(像 int、double、char 等)。
java 中泛型标记符:
- E - Element (在集合中使用,因为集合中存放的是元素)
- T - Type(Java 类)
- K - Key(键)
- V - Value(值)
- N - Number(数值类型)
- ? - 表示不确定的 java 类型
public class GenericMethodTest
{
// 泛型方法 printArray
public static < E > void printArray( E[] inputArray )
{
// 输出数组元素
for ( E element : inputArray ){
System.out.printf( "%s ", element );
}
System.out.println();
}
public static void main( String args[] )
{
// 创建不同类型数组: Integer, Double 和 Character
Integer[] intArray = { 1, 2, 3, 4, 5 };
Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };
System.out.println( "整型数组元素为:" );
printArray( intArray ); // 传递一个整型数组
System.out.println( "\n双精度型数组元素为:" );
printArray( doubleArray ); // 传递一个双精度型数组
System.out.println( "\n字符型数组元素为:" );
printArray( charArray ); // 传递一个字符型数组
}
}
7.IO流
框架
按操作数据单位:字节流(8 bit),字符流(16 bit)
按数据流流向: 输入流 输出流
按流的角色:节点流,处理流
抽象基类 | 字节流 | 字符流 |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
File对象
1. 实例化
Java文件类以抽象的方式代表文件名和目录路径名。该类主要用于文件和目录的创建、文件的查找和文件的删除等。
File对象代表磁盘中实际存在的文件和目录。通过以下构造方法创建一个File对象。
通过给定的父抽象路径名和子路径名字符串创建一个新的File实例。
File(File parent, String child);
通过将给定路径名字符串转换成抽象路径名来创建一个新 File 实例。
File(String pathname)
根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。
File(String parent, String child)
通过将给定的 file: URI 转换成一个抽象路径名来创建一个新的 File 实例。
File(URI uri)
实例
package java_gaoji.IOTest;
import java.io.File;
/*
一、File的使用:
1.File实例化
*/
public class test01 {
public static void main(String[] args) {
//构造器1
File file1 = new File("Hello.txt");//相对路径:当对于当前工程
File file2 = new File("E:\\Sprite\\Desktop\\FileTest");
//构造器2
File file3 = new File("E:\\Sprite","\\Desktop\\FileTest");
//构造器3
File file4 = new File(file3,"\\Desktop\\FileTest");
}
}
2. 方法
创建File对象成功后,可以使用以下列表中的方法操作文件。
序号 | 方法描述 |
---|---|
1 | public String getName() 返回由此抽象路径名表示的文件或目录的名称。 |
2 | public String getParent()****、 返回此抽象路径名的父路径名的路径名字符串,如果此路径名没有指定父目录,则返回 null 。 |
3 | public File getParentFile() 返回此抽象路径名的父路径名的抽象路径名,如果此路径名没有指定父目录,则返回 null 。 |
4 | public String getPath() 将此抽象路径名转换为一个路径名字符串。 |
5 | public boolean isAbsolute() 测试此抽象路径名是否为绝对路径名。 |
6 | public String getAbsolutePath() 返回抽象路径名的绝对路径名字符串。 |
7 | public boolean canRead() 测试应用程序是否可以读取此抽象路径名表示的文件。 |
8 | public boolean canWrite() 测试应用程序是否可以修改此抽象路径名表示的文件。 |
9 | public boolean exists() 测试此抽象路径名表示的文件或目录是否存在。 |
10 | public boolean isDirectory() 测试此抽象路径名表示的文件是否是一个目录。 |
11 | public boolean isFile() 测试此抽象路径名表示的文件是否是一个标准文件。 |
12 | public long lastModified() 返回此抽象路径名表示的文件最后一次被修改的时间。 |
13 | public long length() 返回由此抽象路径名表示的文件的长度。 |
14 | public boolean createNewFile() throws IOException 当且仅当不存在具有此抽象路径名指定的名称的文件时,原子地创建由此抽象路径名指定的一个新的空文件。 |
15 | public boolean delete() 删除此抽象路径名表示的文件或目录。 |
16 | public void deleteOnExit() 在虚拟机终止时,请求删除此抽象路径名表示的文件或目录。 |
17 | public String[] list() 返回由此抽象路径名所表示的目录中的文件和目录的名称所组成字符串数组。 |
18 | public String[] list(FilenameFilter filter) 返回由包含在目录中的文件和目录的名称所组成的字符串数组,这一目录是通过满足指定过滤器的抽象路径名来表示的。 |
19 | public File[] listFiles() 返回一个抽象路径名数组,这些路径名表示此抽象路径名所表示目录中的文件。 |
20 | public File[] listFiles(FileFilter filter) 返回表示此抽象路径名所表示目录中的文件和目录的抽象路径名数组,这些路径名满足特定过滤器。 |
21 | public boolean mkdir() 创建此抽象路径名指定的目录。 |
22 | public boolean mkdirs() 创建此抽象路径名指定的目录,包括创建必需但不存在的父目录。 |
23 | public boolean renameTo(File dest) 重新命名此抽象路径名表示的文件。 |
24 | public boolean setLastModified(long time) 设置由此抽象路径名所指定的文件或目录的最后一次修改时间。 |
25 | public boolean setReadOnly() 标记此抽象路径名指定的文件或目录,以便只可对其进行读操作。 |
26 | public static File createTempFile(String prefix, String suffix, File directory) throws IOException 在指定目录中创建一个新的空文件,使用给定的前缀和后缀字符串生成其名称。 |
27 | public static File createTempFile(String prefix, String suffix) throws IOException 在默认临时文件目录中创建一个空文件,使用给定前缀和后缀生成其名称。 |
28 | public int compareTo(File pathname) 按字母顺序比较两个抽象路径名。 |
29 | public int compareTo(Object o) 按字母顺序比较抽象路径名与给定对象。 |
30 | public boolean equals(Object obj) 测试此抽象路径名与给定对象是否相等。 |
31 | public String toString() 返回此抽象路径名的路径名字符串。 |
3.字符流
FileReader
public int read() throws IOException
//1.实例化file对象,指明要操作的文件
File file2 = new File("E:\\Sprite\\Desktop\\FileTest\\Hello.txt");//相对路径:当对于当前工程
//2、提供具体的流
FileReader fr = new FileReader(file2);
//3. 数据的读入
//read():返回读入的一个字符,如果达到文件末尾,返回-1
int data = fr.read();
System.out.println("data = " + data);
while (data != -1) {
System.out.println((char) data);
data = fr.read();
}
//4、关闭流的操作
fr.close();
优化语法:
public static void main(String[] args) throws IOException {
FileReader fr = null;
try {
//1.实例化file对象,指明要操作的文件
File file2 = new File("E:\\Sprite\\Desktop\\FileTest\\Hello.txt");//相对路径:当对于当前工程
//2、提供具体的流
fr = new FileReader(file2);
//3. 数据的读入
//read():返回读入的一个字符,如果达到文件末尾,返回-1
int data;
while ((data = fr.read()) != -1) {
System.out.println((char) data);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
//4、关闭流的操作
if (fr != null) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public int read(char [] c, int offset, int len)
//read()操作升级,使用read()重载方法
@Test
public void test1() throws IOException {
FileReader fr = null;
try {
//1.实例化file对象,指明要操作的文件
File file2 = new File("E:\\Sprite\\Desktop\\FileTest\\Hello.txt");//相对路径:当对于当前工程
//2、提供具体的流
fr = new FileReader(file2);
//3. 数据的读入
//len = fr.read(cbuf):返回读入cbuf中的字符个数
char[] cbuf = new char[5];
int len;
int data;
while ((len = fr.read(cbuf)) != -1) {
// 错误写法一
// for (int i = 0; i <cbuf.length; i++) {
// System.out.print(cbuf[i]);
// }
//
// //错误方式二
// String str = new String(cbuf);
// System.out.println(str);
for (int i = 0; i < len; i++) {
System.out.print(cbuf[i]);
}
// //方式二:
// String str = new String(cbuf,0,len);
// System.out.println(str);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
//4、关闭流的操作
if (fr != null) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
FileWriter
FileWriter 类从 OutputStreamWriter 类继承而来。该类按字符向流中写入数据。可以通过以下几种构造方法创建需要的对象。
在给出 File 对象的情况下构造一个 FileWriter 对象。
FileWriter(File file)
在给出 File 对象的情况下构造一个 FileWriter 对象。
FileWriter(File file, boolean append)
参数:
- file:要写入数据的 File 对象。
- append:如果 append 参数为 true,则将字节写入文件末尾处,相当于追加信息。如果 append 参数为 false, 则写入文件开始处。
/*
文件写入
*/
@Test
public void test2() throws IOException {
//1、提高File对象,指明写出的文件
File file = new File("Hello1.txt");
// 创建文件
file.createNewFile();
//2.提供FileWriter,用于数据的写出
//如果是true,则在文件原来的内容上追加写入内容。如果是false则不是在后面追加,而是替换原来的文本
FileWriter writer = new FileWriter(file,true);
//3. 向文件写入内容
writer.write("想获取一本三国演义");
writer.write("添加一段文字");
writer.flush();
//4.关闭资源
writer.close();
}
4. 复制文件
字符流
/*
实现文件的复制
*/
@Test
public void test3() throws IOException {
FileReader fr = null;
FileWriter fw = null;
try {
//1、提高File对象,指明写出的文件
File srcfile = new File("E:\\Sprite\\Desktop\\FileTest\\Hello.txt");//读出资源文件
File desfile = new File("Hello1.txt");//写入目标文件
//2.提供FileWriter,用于数据的写出
//如果是true,则在文件原来的内容上追加写入内容。如果是false则不是在后面追加,而是替换原来的文本
fr = new FileReader(srcfile);
fw = new FileWriter(desfile);
//3. 向文件写入内容和写出操作
char[] cbuf = new char[5];
int len;
while ((len = fr.read(cbuf)) != -1) {
fw.write(cbuf, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
//4.关闭资源
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
字节流
复制非文本文件
mp4,jpg,doc
public static void main(String[] args) {
String srcPath = "E:\\Sprite\\Documents\\WorkSpace\\231118006丁辉龙_毕业设计\\设计代码\\dhl-graduation-project\\dhl-graduation-project\\dhl-cinema-face\\src\\assets\\test\\2.mp4";
String desPath = "E:\\Sprite\\Desktop\\FileTest\\海贼王\\叶问.mp4";
copyFile(srcPath,desPath) ;
}
/*
复制非本文文件
*/
@Test
public static void copyFile(String srcPath ,String desPath) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//1.造文件
File srcFile = new File(srcPath);
File desFile = new File(desPath);
//2.造流
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(desFile);
//3.读取字节
byte[] buffer = new byte[100];
int len;
while ((len = fis.read(buffer)) != -1) {
String str = new String(buffer, 0, len);
System.out.print(str);
fos.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//3.关闭资源
try {
if (fis != null) {
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fos != null) {
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
缓冲流(推荐)
- 复制非文本文件
缓冲流 + 字节流
package java_gaoji.IOTest;
import org.junit.Test;
import java.io.*;
/*
缓存流:
BufferIntputStream
BufferOutputStream
BufferReaderStream
BufferWriterStream
*/
public class BufferTest {
public static void main(String[] args) {
long start = System.currentTimeMillis();
String srcPath = "E:\\Sprite\\Documents\\WorkSpace\\231118006丁辉龙_毕业设计\\设计代码\\dhl-graduation-project\\dhl-graduation-project\\dhl-cinema-face\\src\\assets\\test\\2.mp4";
String desPath = "E:\\Sprite\\Desktop\\FileTest\\海贼王\\叶问_copy_Buffer.mp4";
copyFile(srcPath,desPath) ;
long end = System.currentTimeMillis();
System.out.println("复制花费的时间: " + (end - start));
}
/**
* 实现非本文的复制
*/
@Test
public static void copyFile(String srcPath ,String desPath) {
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
//1.造文件
File srcFile = new File(srcPath);
File desFile = new File(desPath);
//2.造流
//2.1 造节点流
FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(desFile);
//2.2 造缓存流
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
//3.读写操作
byte[] buffer = new byte[10];
int len;
while ((len = bis.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.资源关闭
//先关闭外层,再关闭内层的流
try {
if (bos != null) {
bos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (bis != null) {
bis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
//说明:关闭外层的流,内层的流也会自动关闭,所以关闭内层的流可以省略
// fos.close();
// fis.close();
}
}
2.实现文本的复制
缓冲流+字符流
/**
* 实现文本的复制
*/
@Test
public static void FileBufferReader(String srcPath ,String desPath) {
BufferedReader br = null;
BufferedWriter bw = null;
try {
//1.造文件
File srcFile = new File(srcPath);
File desFile = new File(desPath);
//2.造流
//2.1 造字符流
FileReader fr = new FileReader(srcFile);
FileWriter fw = new FileWriter(desFile);
//2.2 造缓存流
br = new BufferedReader(fr);
bw = new BufferedWriter(fw);
//3.读写操作
char[] cbuf = new char[10];
int len;
while ((len = br.read(cbuf)) != -1) {
bw.write(cbuf, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.资源关闭
//先关闭外层,再关闭内层的流
try {
if (bw != null) {
bw.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (br != null) {
br.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
//说明:关闭外层的流,内层的流也会自动关闭,所以关闭内层的流可以省略
// fos.close();
// fis.close();
}
5.转换流
跳过了