JavaIO流、Servlet学习以及案例超详细一看就会(内容为md格式,可复制转成md格式)

## File

java.io.File

### 构造方法:

​    new File(String 路径)
    new File(String 父目录,String 文件名)
    new File(File 父目录对象,String 文件名)

```java
*: 路径分界符 File.separator
*: 绝对路径 和 相对路径
    绝对路径:从盘符或者根目录出发定位我们要的文件 一定以/或者x:开头
    相对路径:从程序认定的主目录出发定位我们的文件
```

### 特等优先级方法:3个

```java
static listRoots() : 列出当前计算机的所有"根目录"

String[] list() : 列出一个目录当中所有的"文件名字"

File[] listFiles() : 列出一个目录当中所有的"文件对象"    "*****"
```

### 一等优先级方法: 12个

​    四个只读操作:      exists()   isFile()  isDirectory()  length()
    三个高危写操作:      delete()   mkdirs()  **renameTo()**
    三个得到系列:      getName()  getParent()  getAbsolutePath()
    两个时间相关:      setLastModified()  **lastModified()**

```java
/**
 * 请将D:\测试\a.txt文件的最后一次修改时间 改为 当前修改时间的一天前
 * File lastModified() setLastModified()
 * 时间戳就是从1970-01-01开始所经过的毫秒数,什么时候获取时间戳,就是到那个时间点所经历的毫秒数
 */
public class FileTest7 {
    public static void main(String[] args) {
        File file = new File("D:\\测试\\a.txt");
        long lastModified = file.lastModified();
        long day = 24L*60*60*1000; //一天所经过的毫秒数
        file.setLastModified(lastModified-day);
    }
}
```

## 时间戳如何解析:

```java
1st java.util.Date
        构造方法传参可以指定要表达的时间
        getYear()   getMonth()    getDate()
        getHours()  getMinutes()  getSeconds()

2nd java.util.Calendar
    如何得到实例:不能new 只能Calendar.getInstance();
    调整时间:setTimeInMillis(时间戳);
    得到数据:get(x)   获取的是该对象创建时的时间,是静态的不随时间变化而变化。
        x: 1 2+1 5 11 12 13      7-1

3rd java.text.SimpleDateFormat 
    构造方法要求指定日期格式:yyyy-MM-dd HH:mm:ss
    如果已经有时间戳 想要 字符串: format()
    如果已经有字符串 想要 时间戳: parse() + getTime()
```

## 递归遍历攻略帖

01.我们需要一个能够过滤所有子目录的过滤器 - 最好使用单例 [醉汉式]
    FileFilter  public boolean accept(File file){}

02.我们需要一个能够过滤所有目标文件的过滤器 - 最好使用单例 [懒汉式]

03.这里才是真正的核心 那个递归调用的方法
    方法的参数 代表当前正要对付的那个目录

```c++
3-1: 利用1st开发完成的过滤器 过滤目标目录当中所有的子目录
3-2: 利用2nd开发完成的过滤器 过滤目标目录中所有目标文件
3-3: 判断3-1或者3-2得到的是不是为空 防止没有权限导致空指针异常
3-4: 遍历每个3-1得到的子目录 再次调用03方法
3-5: 遍历3-2得到的每个目标文件 进行对应的操作
```

04.主方法当中利用listRoots()得到当前计算机的所有根目录
    遍历每个根目录 依次调用03那个方法

```java
/**
 * 1)递归遍历文件
 * 2)将文件放到集合中
 * 3)按照文件名从长到短对集合进行排序
 */
public class FileFilterTest2 {
    private static List aList = new ArrayList<String>();
    
    public static void main(String[] args) {
        File dir = new File("D:\\jdk-src");
        File[] files = dir.listFiles();
        for (File file : files) {
            kiss(file);
        }
        System.out.println("文件名最长的为:"+aList.get(0));
        System.out.println("src文件夹文件个数为:"+aList.size());
    }
    //递归遍历
    public static void kiss(File tar) {
        File[] f1 = tar.listFiles((x) -> x.isDirectory());
        File[] f2 = tar.listFiles((x) -> x.isFile());
        if (f1 == null || f2 == null) return;
        for (File file : f1) {
            kiss(file);
        }
        for (File file : f2) {
            aList.add(file.getName());
        }
        Collections.sort(aList, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o2.length() - o1.length();
            }
        });
    }
}
```

# day02

## 字节IO流

IO流    I=Input=输入    O=Output=输出 

    流:数据从源点传输到汇点的管道

流的分类:
    按照方向分:  输入流  /  输出流        参照物:当前程序
    按照单位分:  字节流  /  字符流
    按照功能分:  节点流  /  过滤流(包装流、处理流)

让我们一起上路:
    
InputStream    所有字节输入流统一的父类 抽象类
    int read()
    int read(byte[] data)             *****
    int read(byte[] data,int off,int len)

OutputStream    所有字节输出流统一的父类 抽象类
    write(int data)
    write(byte[] data)
    write(byte[] data,int off,int len)    *****


FileInputStream        输入流 字节流 节点流
FileOutputStream    输出流 字节流 节点流
    *: 它们都是节点流 构造方法允许传入String路径或者File对象
    *: 它们都是节点流 但是只能连接文件 不能连接目录
        否则直接出现异常 FileNotFoundException
    ***: FileInputStream 最常用的是read(byte[] data)** 
    ***: FileOutputStream 最常用的却是write(byte[],int,int)**
    *: FileInputStream 以-1作为读取结束的标识
    *: FileOutputStream 是节点输出流
        **节点输出流创建对象的时候 如果其连接的文件不存在**
        **也会在创建流的第一时间 自动创建 不用手建**
        其实File类当中有个方法createNewFile()    咱没讲!
        但是 如果其连接的目录结构都不存在 
            不但不给创建 还会出现异常
        所以File类当中有个方法**mkdirs**()         一等优先级!
    *: FileOutputStream 是节点输出流 
        **节点输出流是非常可怕的 它极具杀伤力**
        **如果其创建对象的时候 连接的文件已经存在**
        **也会在创建流的那一刻** **被新的空白文件直接替换**
        **如果我们的需求是不想替换** 
        **只想在原有内容的最后** **继续追加新内容**
        **可以构造方法传参 指定追加模式开启**
          **new FileOutputStream("focus.txt",true);**
    *: 用完流的第一时间 请及时关闭流 以解除文件的占用状态
    

BufferedInputStream        输入流 字节流 过滤流 
BufferedOutputStream        输出流 字节流 过滤流
    *: **作为过滤流的它们 是为了给原本的流添加缓冲空间**
        **从而提高每次读写的吞吐量** **进而提高效率**
    *: **作为过滤流的它们** **不能直接连接文件** **只能连接其它的流**
    *: **BufferedInputStream** **最常用的** read() 读取一个字节
    ***: BufferedOutputStream 最常用的write(int data) 写出一个字节**
    *: BufferedInputStream 以-1作为读取结束的标识
    *: BufferedOutputStream 是带缓冲的输出流
        使用带缓冲的输出流 务必注意及时清空缓冲
        以防止数据滞留缓冲区 导致丢失!
        缓冲区什么条件下会清空:
             **1.满了自动清空 无需操作**
            **2.关闭流的操作 会触发清空缓冲**
            **3.主动清空缓冲 flush();**
    

DataInputStream        输入流 字节流 过滤流
DataOutputStream    输出流 字节流 过滤流
    *: 它们给原本的流添加读写基本数据类型的功能
    *: 作为过滤流的它们 不能直接连接文件 只能连接其它的流

```Java
boolean char byte short int long float double
*: DataInputStream 提供的核心方法 readXxxx()    有返回值
*: DataOutputStream 提供的核心方法 writeXxxx()    要参数
*: DataInputStream 不能再以-1作为读取结束的标识了
    如果一旦到达文件结尾 还继续尝试读取
    将会直接触发EOFException => End Of File
```

## 字节IO小总结

InputStream        所有字节输入流统一的父类 抽象类
OutputStream        所有字节输出流统一的父类 抽象类

FileInputStream        节点流
FileOutputStream    节点流        *****
    **节点输出流创建对象的时候 连接的文件如果不存在 它能自己建**
        **如果已经存在 它还建 它用新的覆盖你的老文件!!!**

BufferedInputStream    过滤流==包装流==处理流
BufferedOutputStream    过滤流==包装流==处理流
    它们给原本的流添加缓冲空间 从而提高每次读写的吞吐量 
        进而减少了往返的次数 从而提高了效率
    *:**BufferedOutputStream 带缓冲的输出流 务必注意清空缓冲**

DataInputStream        过滤流==包装流==处理流
DataOutputStream    过滤流==包装流==处理流
    它们给原本的流添加读写基本数据类型的功能
        DataInputStream => readXxx()  
        DataOutputStream => writeXxxx()

## 学好IO流必须要会做的8大需求


```java
1> 使用标准的节点流 配合一个自定义的大数组 完成文件复制 [*]
    FileInputStream + FileOutputStream
    *: 标准TWR        *: 连环try

2> 使用带缓冲的过滤流 一次一个字节的完成文件复制
    BufferedInputStream + BufferedOutputStream
    *: 标准TWR        *: 连环try

3> 将内存当中一个基本数据类型变量 保存到磁盘中去
    DataOutputStream    writeXxxx()
    *: 标准TWR        *: 连环try        

4> 从文件当中读取一个基本数据类型变量 到程序当中
    DataInputStream    readXxxx();
    *: 标准TWR        *: 连环try

5> 将内存当中一个引用类型的对象 保存到磁盘中去
    ObjectOutputStream    writeObject();
    *: 标准TWR        *: 连环try

6> 从文件当中读取一个引用类型的对象 到程序当中
    ObjectInputStream    readObject()
    *: 标准TWR        *: 连环try
    
7> 以一行为单位的写出文本文件            [*****]
    PrintWriter         println()
    *: 标准TWR        *: 连环try

8> 以一行为单位读取文本文件            [*****]
    BufferedReader        readLine()     null
```

# day03 对象流+字符流

基本数据类型 如何保存到文件当中 如何读取到程序当中

引用数据类型 如何保存到文件当中 如何读取到程序当中

DataInputStream        读取基本数据类型的功能
DataOutputStream    写出基本数据类型的功能

ObjectInputStream    读取引用数据类型的功能    输入流 字节流 过滤流    
ObjectOutputStream    写出引用数据类型的功能    输出流 字节流 过滤流
    *: 作为过滤流的它们 是为了给原本的流添加读写对象的功能的
    *: 作为过滤流的它们 不能直接连接文件 只能连接其它的流
    *: ObjectInputStream 核心方法 readObject()    有返回值
    *: ObjectOutputStream 核心方法 writeObject()    要参数
    *: ObjectInputStream 同样不以-1作为读取结束的标识
        而是一旦到达文件结尾 再继续尝试读取 
        将会直接触发EOFException => End Of File
    *: 想要持久化 必须先要序列化
        想要持久化到磁盘上的对象的类型 必须实现序列化接口
            **implements Serializable**
        如果要持久化的对象当中有其它引用类型的属性
        这些属性的类型也必须实现序列化接口
        如果某些属性无关紧要 不需要参与持久化
        可以使用transient修饰 
            transient = 短暂的 转瞬即逝的 不参与持久化的
    *: 如果要持久化保存的是一个集合对象
        则必须保证集合当中存放的元素的类型都实现了序列化接口
        如果是个使用了比较器的TreeSet或者TreeMap
        就连比较器的类型也必须要实现序列化接口
        (因为比较器是TreeSet或者TreeMap的一个属性)

## 字符IO流

Reader         所有字符输入流统一的父类 抽象类
    int read()
    int read(char[] data)
    int read(char[] data,int off,int len)

Writer        所有字符输出流统一的父类 抽象类
    write(int data)
    write(char[] data)
    write(char[] data,int off,int len)

FileReader        字符流 输入流 节点流
FileWriter        字符流 输出流 节点流
    *: 它们都是节点流 构造方法允许传入String路径 / File对象
    *: 尽管他们都是节点流 但是只能连接文件不能连接目录
        否则直接触发FileNotFoundException
    *: FileReader 最常用的是read(char[])
    *: FileWriter 最常用的却是write(char[],int,int)
    *: FileWriter 同样是个节点输出流
        节点输出流创建对象的时候 如果连接的文件不存在
        也会自己创建出来 
        但是如果连接的目录结构都不存在 将直接异常
        节点输出流是具有极强的杀伤性的
        创建对象的时候 如果连接的文件已经存在
        也会在创建的那一刻 被新的空白文件直接覆盖
        如果需求是在原有内容的最后 继续追加新内容
        则构造方法传参 指定追加模式:
            new FileWriter("a.txt",true);
    *: FileReader 以-1作为读取结束的标识
    *: 用完流第一时间关流 以解除文件的占用状态

BufferedReader        输入流 字符流 过滤流            *****
BufferedWriter        输出流 字符流 过滤流
    *: 作为过滤流的它们 是为了给原本的流添加变长的缓冲空间
        从而实现以一行(hang)为单位的读写
    *: 作为过滤流的它们 不能直接连接文件 只能连接其它的流
    *: BufferedReader    String readLine()
    *: BufferedWriter    write(String str) + newLine()
    *: BufferedReader 以null作为读取结束的标识
    *: BufferedWriter 是带缓冲区的输出流
        请务必注意及时清空缓冲 以防止数据滞留缓冲空间
            1> 满了自动清空 
            2> 关闭流的操作触发清空缓冲
            3> flush();


PrintWriter 比 BufferedWriter 强大在哪些方面    
    *:PrintWriter 既可以当做节点流 又可以当做过滤流
        构造方法允许传入 String路径 / File文件 / 流
    *:PrintWriter 既可以连接字节流 又可以连接字符流
        构造方法允许传入 OutputStream / Writer
    *:**当做节点流使用的时候 构造方法第二个参数**
        **可以指定字符编码**  
        new PrintWriter("a.txt","**utf-8**");
    *:**当做过滤流使用的时候 构造方法第二个参数**
        **允许指定自动清空缓冲**
        new PrintWriter(new FileWriter("a.txt"),**true**); //AutoFlush
    *:它的一个 println() == write() + newLine()
    *:我们对它的孪生兄弟 非常熟悉  System.out  PrintStream

```Java
综上所述 我们需要以一行为单位写出文本文件的时候
    不会使用BufferedWriter 而会使用PrintWriter
```

## 小补充

01.能再解释一遍 FileInputStream 和 BufferedInputStream
    为什么以-1作为读取结束的标识 
    但是DataInputStream不行?
    

```java
FileInputStream和BufferedInputStream 的read()返回的是编码
    编码是不会有-1的 所以可以利用-1作为结束的标识

DataInputStream 它能够读取基本数据类型
    byte short int long 四种类型都可能会出现-1的值
    如果用-1作为结束标识 那么真读到-1咋办呢
```


02.HelloWorld限次执行10次 收费的那个return可以不用写吗?
    不是非得加return 但是要控制后界面的代码逻辑不执行
    要么return 要么else~

03.
    File[] ds = tar.listFiles((x) -> x.isDirectory());
    File[] fs = tar.listFiles((x) -> x.isFile());
    if(ds == null) return;

```java
这其中为什么一个为空就可以结束

你的ds 和 fs 其实都是tar.listFiles()得到的
它们在tar代表的那个目录没有权限的情况下 会直接返回null
如果fs是null 则ds必然也是null 
```


​    

# day04 复习

## 两个异常

01.文件复制目标文件出现 “ 过大 ” 或者 “ 过小 ” 是由于什么原因造成的
    过大:没有使用三参数的write(byte[],int,int)
        我们应该实际读取到多少个字节就写出多少字节
        不能把整个数组都直接写出
    过小:使用了带缓冲区的输出流 没有及时清空缓冲

02.再讲一下InvalidClassException是在什么条件下触发的?
    写出对象的时候和读取对象的时候
    类当中属性或方法做了修改 所以导致**序列化的唯一编号**
    **前后不一致**!

## InputStreamReade 桥转换器

```java
FileInputStream fis = new FileInputStream("abc.txt");
InputStreamReader r = new InputStreamReader(fis,"utf-8");
BufferedReader br = new BufferedReader(r);
```

## RandomAccessFile

RandomAccessFile 既是字节输入流,又是字节输出流,是节点流。

```java
RandomAccessFile raf = new RandomAccessFile("d:\etoak.mp4","rw"); //设置"rw"  代表读写功能
        raf.setLength(50L<<30); //设置文件大小,L是为了防止内存溢出而加的  不加L会报异常
        raf.close();
```

## 拓展

```java
URL url = new URL("http://old.etoak.com/assets/images/zkcs.png");
        URLConnection uc = url.openConnection();
        InputStream is = uc.getInputStream();
```

# day05

**Stream流,是Java8的新特性,可以修改集合流中的数据但是不会改变原先集合中的数据**

## Stream流使用案例(lambda表达式必会)

单列集合:集合对象.stream()

```java
        List<Integer> list = new ArrayList<>();
        Stream<Integer> stream = list.stream();
```

数组:Arrays.stream(数组) 或者 使用Stream.of()来创建

```java
Integer []arr={1,2,3,4};
Stream<Integer> stream = Arrays.stream(arr);
Stream<Integer> stream = Stream.of(arr);
```

双列集合:转换成单列集合后再创建

```java
//map集合获取Steam流的方式 map.entrySet().stream();
Set<Map.Entry<String, Integer>> entries = map.entrySet();
Stream<Map.Entry<String, Integer>> thisMap = entries.stream();
```

​    

## 案例一:List集合获取流

```java
/**
    使用Steam流过滤掉List集合中不符合条件的数据
    将过滤后的数据添加到新的集合当中去
**/
public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        List<Integer> aList = new ArrayList<>();
    
        for (int i=0;i<10;i++){
            if (i==5)
                list.add(i);
            if (i==6)
                list.add(i);
            list.add(i);
        }
    
        list.forEach(integer -> System.out.print("  " + integer));
        //单列集合(例如List)获取流的方式 list.stream();
        list.stream()
                .distinct()  //去重
                .filter(integer -> integer>7)    //根据条件过滤
                .forEach(integer -> aList.add(integer));  //遍历并进行相关操作
    
        aList.forEach(integer -> System.out.println("integer = " + integer));
    }

```

## 案例二:Map集合获取流

```java
/**
    根据条件对map集合进行筛选
**/
public static void main(String[] args) {
        HashMap<String, Integer> map = new HashMap<>();
        map.put("大一",18000);
        map.put("大二",18500);
        map.put("大三",19000);
        map.put("大四",20000);
        //map集合获取Steam流的方式 map.entrySet().stream();
        Set<Map.Entry<String, Integer>> entries = map.entrySet();
        Stream<Map.Entry<String, Integer>> thisMap = entries.stream();

        thisMap.filter(entry -> entry.getValue()> 18666)
                .forEach(entry -> System.out.println(entry.getKey()+" "+entry.getValue()));
    }
```

## 案例三:List集合流map()的使用

```java
/**
    将List流中的数据进行转换
    即将原先流中的Student类型的数据转换成String类型
**/
public class LambdaAndStreamT3 {
    public static void main(String[] args) {
        ArrayList<Student> list = new ArrayList<>();
        list.add(new Student("张三",18,'男'));
        list.add(new Student("李四",22,'男'));
        list.add(new Student("王五",25,'男'));
        list.stream()
                .filter(student -> student.getAge()>20)
                .map(student -> student.getName())
                .forEach(s -> System.out.println("name = " + s));
    }
}

@Data
@AllArgsConstructor
class Student{
    private String name;
    private int age;
    private char sex;
}

```

**distinct()方法的使用,底层依靠的是Object的equals()方法**

​    返回由该流的不同元素(根据 Object.equals(Object) )组成的流。

## 案例四:使用sorted方法进行排序

**sorted()方法可以对流中的元素进行排序,并且要求流中不能有重复的元素**

​    先去重,后排序

​    **注意**:如果调用空参的sorted()方法,需要流中的元素是实现了Comparable接口

```java
public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        for (int i=0;i<10;i++){
            if (i==5)
                list.add(i);
            if (i==6)
                list.add(i);
            list.add(i);
        }

        list.add(18);
        list.add(22);
        list.add(11);
        
        list.stream()
                .distinct()
                .sorted((o1, o2) -> o1 - o2)
                .forEach(integer -> System.out.println("integer = " + integer));
    }

================================================================================================
    
```

## 案例五:limit()方法可设置流的最大长度,超出部分将被抛弃

```java
/**
 * 对流中的元素按照年龄进行排序
 * 并且要求不能有重复的元素
 * 然后打印其中年龄最大的两名作家的姓名。
 */
public class LambdaAndStreamT4 {
    public static void main(String[] args) {
        List<Teacher> list = new ArrayList<>();
        list.add(new Teacher("张三",29,'女'));
        list.add(new Teacher("王五",38,'男'));
        list.add(new Teacher("赵六",27,'男'));
        list.add(new Teacher("老八",32,'男'));
        list.add(new Teacher("李四",42,'男'));
        list.stream()
                .distinct()
                .sorted((t1, t2) -> t2.getAge() - t1.getAge())
                .limit(2)
                .forEach(teacher -> System.out.println("teacher = " + teacher));
    }
}

@Data
@AllArgsConstructor
class Teacher{
    private String name;
    private int age;
    private char sex;
}
```

## 案例六:skip(n)方法,跳过流中的前n个元素,返回剩下元素

```java
/**
 * 打印除了年龄最大的作家外的其他作家
 * 要求不能有重复元素
 * 并且按照年龄降序排序
 */
public class LambdaAndStreamT5 {
    public static void main(String[] args) {
        List<Man> list = new ArrayList<>();
        list.add(new Man("张三",29,'女'));
        list.add(new Man("王五",38,'男'));
        list.add(new Man("赵六",27,'男'));
        list.add(new Man("赵六",27,'男'));
        list.add(new Man("李四",42,'男'));

        list.stream()
                .distinct()
                .sorted((m1,m2)->m2.getAge()-m1.getAge())
                .skip(1)
                .forEach(man -> System.out.println("man = " + man));
    }
}

@Data
@AllArgsConstructor
class Man{
    private String name;
    private int age;
    private char sex;
}
```

**PrintStream PrintWriter**

# day07

java.net.Socket => 套接字

    一根电话线 .. 包含两股线

CS架构的软件: 
    Client - Server   客户端和服务器

## 服务器端:

​    0.预留一个线程池执行器
    1.创建ServerSocket对象
    2.循环当中不停的调用ServerSocket的accept()接收客户端连接
    3.将Socket连接对象 委托给一个线程 并且将线程提交给执行器
        *: 根据需求得到对应的输入流或者输出流
        *: 对流进行相应的包装和处理 (包装流)
        *: 调用对应流的对应的核心方法 读写数据
        *: 关关关

## 客户端:

​    1.直接创建Socket对象 并且指定要连接的IP地址和端口号
    2.根据需求得到对应的输入流或者输出流
    3.对流进行相应的包装和处理 (包装流)
    4.调用对应流的对应的核心方法 读写数据
    5.关关关

## 练习1:客户端服务器相互传数据

```java
/**
 * 服务器获取客户端传来的歌曲名
 * 然后服务器找到该文件
 * 接下来服务器将该文件
 */
public class ServerTest7 {
    public static void main(String[] args) throws Exception {
        //创建一个60025端口的Socket对象
        ServerSocket socket = new ServerSocket(60025);
        //创建连接池对象
        ExecutorService ec = Executors.newCachedThreadPool();
        //创建一个标记服务器运行状态的布尔值
        boolean isRunning = true;
        while (isRunning) {
            //服务器阻塞在此
            Socket waiter = socket.accept();
            //创建
            MyServerTestThread mst = new MyServerTestThread(waiter);
            ec.submit(mst);
        }
        ec.shutdown();
        socket.close();
    }
}

class MyServerTestThread extends Thread {
    private Socket socket;

    public MyServerTestThread(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            //获取输入流,拿到客户端传来的歌曲名
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String name = br.readLine();
            //创建文件对象
            File dir = new File("D:\\11\\day07\\MusicPlatform\\mp3");
            //拿到以.MP3结尾的歌曲文件
            File[] files = dir.listFiles(f -> f.isFile() && f.getName().toLowerCase().endsWith(".mp3"));
            //遍历files对象数组
            for (File file : files) {
                //拿到遍历的文件名
                String name1 = file.getName();
                String name2 = name1.substring(0, name1.lastIndexOf("."));
                //对比文件名  如果相同那么读文件  然后将文件写出到客户端
                if (name2.equals(name)) {
                    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
                    BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
                    byte[] bytes = new byte[1024];
                    int len;
                    while ((len = bis.read(bytes)) != -1) {
                        bos.write(bytes, 0, len);
                    }
                    bos.close();
                    bis.close();
                }
            }
            br.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}
```

```java
package com.ls.test1;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;

/**
 * 向服务器传输歌曲名
 * 获取服务器返回的数据
 * 并保存到d:\\11目录下的aaa.MP3
 */
public class ClientTest7 {
    public static void main(String[] args) throws Exception {
        Socket socket = new Socket(InetAddress.getLocalHost(),7777);
        PrintWriter pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()),true);
        Scanner input = new Scanner(System.in);
        String name = input.nextLine();
        pw.println(name);
        System.out.println("name = " + name);

        BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\11\\aaa.mp3"));
        byte []bytes=new byte[1024];
        int len;
        while ((len=bis.read(bytes))!=-1){
            bos.write(bytes,0,len);
        }
        bos.close();
        bis.close();
        pw.close();
        input.close();
        socket.close();
    }
}

```

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值