多线程使用HashMap,HashMap和HashTable和ConcurrentHashMap区别(面试题常考),硬盘IO,顺便回顾volatile(二)

简介: 多线程使用HashMap,HashMap和HashTable和ConcurrentHashMap区别(面试题常考),硬盘IO,顺便回顾volatile

文件命名,也可以起到文件移动的效果

以上文件系统操作,都是基于File类完成的。

文件流stream-主要原因,操作系统流

文件内容的操作核心步骤,四个

1.打开文件 fopen                            

2.关闭文件 fclose

3.读文件     fread

4.写文件     fwrite

JavaIO流是庞大的体系,涉及非常多的类,不同的类有不同的特性,使用方法基本类似。

字节流:InputStream,OutputStream ,后续的一些操作字节的类都是衍生自这两个类,以操作字节为单位(二进制文件)

字符流: Reader Write 操作字符为单位(文本文件)

reader.close:让一个进程打开一个文件,是要从系统中一定的资源(占据进程pcb文件描述符中的一个表项文件描述符是顺序表(长度有限,不可扩容),如果不释放,就会出现“文件资源泄露”这是很严重的问题,一旦一直打开文件,而不去关闭不用的文件,文件描述符就会被占用满(导致服务器宕机)后续无法打开新的文件)->年终奖消失大法

我们平时可以使用try catch finally {close}但是不够优雅

最好使用try with resources

  //这个就如同sychronized一样,自动给你关闭文件,但是这块写的不完全,需要写使用资源的操作
try(Reader reader=new FileReader("d:/test.txt"))

read()一次读一个字符<->char(按照Integer来表示,表示两个字符的范围,-1表示已经读取完毕eof了)

可能会有疑问——utf8格式一个字符三个字节,为什么读出字符是两个字节呢

java的char类型是用unicode编码的(一个字符,两个字节),使用完这个方法读取一个字符,java标准库内部会帮我们自动转换!unicode和utf8(一个字符)是不同的。

这个会把读到的内容,填充到参数cbuf是数组中,此处的参数,相当于一个“输出型参数”

char buf[]=new char[1024];

reader.read(buf)//这种写法java中不太常见(c++)使用偏多,通过read,就会把一个本来空的数组,填充上内容

read(char[]cbuf,int off,int len)

多个小文件,都需要读取且需要拼接到一起,就用这个方法,比如三个文件,大小都是100字节

read(cbuf,0,100)
read(cbuf,100,100)
read(cbuf,200,100)

我们如同下图那样,先读取txt文件,然后在去依次输出这个字符串,读到文件末尾退出

import java.io.*;
public class Demo12 {
    public static void main(String[] args) throws IOException {
        try(Reader reader=new FileReader("/Users/lcl/untitled7/src/test.txt")){
            while(true){
                char buf[]=new char[1024];
                int n=reader.read(buf);
                if(n==-1){
                    System.out.println("读到文件末尾");
                    break;
                }
                for(int i=0;i<n;i++){
                    System.out.println(buf[i]+",");
                }
//String构造方法内部,默认是utf8(但是你可以让他变成gbk
String s=new String(0,n,"gbk");
                String s=new String();
                System.out.println(s);
            }
        }
    }
}

read(byte[]b)->一次读若干字节,填满数组的一部分

Scanner一视同仁,只是把当前读到的字节数据进行转换~(不关心这个数据来自于标准输入,还是来自文件或者网卡)

以前学过的Scanner只是读文本文件的,不适合读二进制文件,在标准库中,还提供了一些具体工具类,辅助更方便的读写二进制文件。

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;
public class Demo13 {
    public static void main(String[] args) throws IOException {
        try(InputStream inputStream=new FileInputStream("/Users/lcl/untitled7/src/test.txt")){
            Scanner scanner=new Scanner(inputStream);
//第一段到空格之前的字符串,读取test文件读取数据
            String s= scanner.next();;
            System.out.println(s);
            String s1= scanner.next();;
            System.out.println(s1);
第二段空格之前,相当于读取一个词
            String s2= scanner.next();;
            System.out.println(s2);
        }
    }
}

输出,使用方法和输入十分相似——

关键的操作是write,write之前要打开文件,用完需要关闭文件,输出流对象(无论字节流还是字符流)会打开文件之后,清空文件内容!正如我们之前那么写的i,变成了我喜欢你

但是我们假如想在他的后面去写,而不去自动删除,该怎么做呢,可以追加写,此时就不进行清空操作。OutputStream使用方式完全一样,只不过write方法不能支持“字符串参数”。,只能按照字节或者字节数组写入。

Scanner搭配InputStream可以简化代码效果(可以不像我们之前那么一点一点读)

PrintWriter(sout,点击里面的out,她就是这个类,使用一系列方法printf,println)搭配OutputStream

经典面试题,写个代码递归目录

深度优先-DFS(先中后序,递归)

广度优先-BFS(层序)

import java.io.File;
import java.util.Scanner;
public class Demo15 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入搜索的根目录");
        File rootPath = new File(scanner.next());
        System.out.println("请输入删除的关键词");
        String word = scanner.next();
        if (!rootPath.isDirectory()) {
            System.out.println("路径不合法");
            return;
        }
        scanDir(rootPath, word);
        scanner.close();
    }
    public static void scanDir(File currentDir, String word) {
        //先列出当前目录包含哪些内容
        File[] files = currentDir.listFiles();
        if (files == null || files.length == 0) {
            //空目录/非法目录
            return;
        }
        for (File f : files) {
            System.out.println(f.getAbsolutePath());
            if (f.isFile()) {
                //3看当前文件是普通文件,看文件名字,是否包含word,来决定是否删除
                dealFile(f, word);
            } else {
                //4假如是当前文件是目录文件(文件夹)就再次递归,直到找到文件。
                scanDir(f, word);
            }
        }
    }
    private static void dealFile(File f, String word) {
        //是根据文本的是名字删除,假如不存在就返回
        if (!f.getName().contains(word)) {
            return;
        }
        //打印删除文件的路径
        System.out.println("要删除的文件:" + f.getAbsolutePath());
        f.delete();
    }
}

2.进行普通文件的复制,把一个文件复制成另一个文件

在这之前我们先要想一个问题,读文件一次读1024好,还是20480好?

每次read都是访问硬盘,此时把buffer(接受的数组)变大,就能降低访问硬盘次数提高效率,buffer大的前提,空间需要充足

import java.io.*;
import java.util.Scanner;
public class Demo16 {
    public static void main(String[] args) throws IOException {
        System.out.println("请输入复制的文件路径");
        Scanner scanner = new Scanner(System.in);
        String src = scanner.next();
        File srcFile = new File(src);
        if (!srcFile.isFile()) {
            System.out.println("源文件不存在或者不是一个文件");
            return;
        }
        System.out.println("请输入复制目标文件路径");
        String dest = scanner.next();
        File destFile = new File(dest);
        //不要求目标文件本身存在,但要保证目标文件所在的目录所在。
        //假设目标文件写作d:/tmp/cat2.jpg,就需保证d:tmp目录所在
        if (!destFile.getParentFile().isDirectory()) {
            System.out.println("您的路径非法");
            return;
        }
//输入流,输出流,按照字节流方式去打开这个文件
        try (InputStream inputStream = new FileInputStream(srcFile);
            OutputStream outputStream = new FileOutputStream(destFile)) {
            while(true)
                {
                    byte[] buffer = new byte[1024];
                    int n = inputStream.read(buffer);
                    System.out.println("n=" + n);
                    if (n == -1) {                    //读完事了
                        System.out.println("读到eof,结束"); 
                        break;
                    }
//从0开始,写n这么长
                    outputStream.write(buffer, 0, n);
                }
            }
        }
    }
相关文章
|
16天前
|
存储 安全 算法
HashMap和Hashtable有什么区别?
处理网https://www.91chuli.com/
|
6月前
|
存储 安全 Java
Java 集合框架中的老炮与新秀:HashTable 和 HashMap 谁更胜一筹?
嗨,大家好,我是技术伙伴小米。今天通过讲故事的方式,详细介绍 Java 中 HashMap 和 HashTable 的区别。从版本、线程安全、null 值支持、性能及迭代器行为等方面对比,帮助你轻松应对面试中的经典问题。HashMap 更高效灵活,适合单线程或需手动处理线程安全的场景;HashTable 较古老,线程安全但性能不佳。现代项目推荐使用 ConcurrentHashMap。关注我的公众号“软件求生”,获取更多技术干货!
108 3
|
7月前
|
安全
HashTable与HashMap的区别
(1)HashTable的每个方法都用synchronized修饰,因此是线程安全的,但同时读写效率很低 (2)HashTable的Key不允许为null (3)HashTable只对key进行一次hash,HashMap进行了两次Hash (4)HashTable底层使用的数组加链表HashTable与HashMap的区别
112 2
|
7月前
|
安全
ConcurrentHashMap原如何保证的线程安全?
JDK1.7:使用分段锁,将一个Map分为了16个段,每个段都是一个小的hashmap,每次操作只对其中一个段加锁 JDK1.8:采用CAS+Synchronized保证线程安全,每次插入数据时判断在当前数组下标是否是第一次插入,是就通过CAS方式插入,然后判断f.hash是否=-1,是的话就说明其他线程正在进行扩容,当前线程也会参与扩容;删除方法用了synchronized修饰,保证并发下移除元素安全
187 2
|
3月前
|
存储 网络协议 安全
Java网络编程,多线程,IO流综合小项目一一ChatBoxes
**项目介绍**:本项目实现了一个基于TCP协议的C/S架构控制台聊天室,支持局域网内多客户端同时聊天。用户需注册并登录,用户名唯一,密码格式为字母开头加纯数字。登录后可实时聊天,服务端负责验证用户信息并转发消息。 **项目亮点**: - **C/S架构**:客户端与服务端通过TCP连接通信。 - **多线程**:采用多线程处理多个客户端的并发请求,确保实时交互。 - **IO流**:使用BufferedReader和BufferedWriter进行数据传输,确保高效稳定的通信。 - **线程安全**:通过同步代码块和锁机制保证共享数据的安全性。
142 23
|
8月前
|
存储 开发者
HashMap和Hashtable的key和value可以为null吗,ConcurrentHashMap呢
HashMap的key可以为null,value也可以为null;Hashtable的key不允许为null,value也不能为null;ConcurrentHashMap的key不允许为null
|
8月前
|
Dubbo Java 应用服务中间件
剖析Tomcat线程池与JDK线程池的区别和联系!
剖析Tomcat线程池与JDK线程池的区别和联系!
332 0
剖析Tomcat线程池与JDK线程池的区别和联系!
|
9月前
|
NoSQL 网络协议 Unix
1)Redis 属于单线程还是多线程?不同版本之间有什么区别?
1)Redis 属于单线程还是多线程?不同版本之间有什么区别?
213 1
|
8月前
|
缓存 算法 Java
Java 中线程和纤程Fiber的区别是什么?
【10月更文挑战第14天】
221 0
|
10天前
|
存储 安全 Java
Java 集合面试题从数据结构到 HashMap 源码剖析详解及长尾考点梳理
本文深入解析Java集合框架,涵盖基础概念、常见集合类型及HashMap的底层数据结构与源码实现。从Collection、Map到Iterator接口,逐一剖析其特性与应用场景。重点解读HashMap在JDK1.7与1.8中的数据结构演变,包括数组+链表+红黑树优化,以及put方法和扩容机制的实现细节。结合订单管理与用户权限管理等实际案例,展示集合框架的应用价值,助你全面掌握相关知识,轻松应对面试与开发需求。
65 3

热门文章

最新文章