【2024年7月21号学习汇总】

P1162填涂颜色

 


---------------------------------------------------------------------------------------------------------------------------------

解题思路:

*1.从外围区域开始拓展,输入区域为(1~~n)*(1~~n);外围区域为(0~~n+1)*(0~~n+1)

2.从原点(0,0)开始进行拓展,当拓展遇到1时就不再进行拓展;

3.拓展的点都在标记数组中标记为0;

4.被'1'围住的数据不作标记;

---------------------------------------------------------------------------------------------------------------------------------

#include <iostream>
using namespace std;
int a[32][32], b[32][32];
int dx[5] = { -1,1,0,0 };//对数据进行拓展(上,下,左,右)
int dy[5] = { 0,0,-1,1 };
int n, i, j;
void dfs(int p, int q) {
    int i;
    if (p<0 || p>n + 1 || q<0 || q>n + 1 || b[p][q] != 0)//不在范围为内的数据则不标记
        return;//作用相当于break;
    b[p][q] = 1;
    for (i = 1; i <= 4; i++)
        dfs(p + dx[i], q + dy[i]);//进一步拓展;
}
int main() {
    cin >> n;//输入n,表示n*n的矩阵;
    for (i = 1; i <= n; i++)
        for (j = 1; j <= n; j++) {
            cin >> a[i][j];
            if (a[i][j]==0)//如果拓展到的数据为0则在标记数组里标记为0
                b[i][j] = 0;
            else b[i][j] = 1;//如果输入数据为一则标记该点为一;
        }
    dfs(0, 0);//进行拓展
    for (i = 1; i <= n; i++) {//输出部分
        for (j = 1; j <= n; j++)
            if (b[i][j] == 0)
                cout << 2 << ' ';//如果没有被便利,则输出2;
            else
                cout << a[i][j] << ' ';
        cout << endl;
    }
}

文件与IO

 File

如果我们想使用 Java 代码来操作文件,就需要使用到 java.io.File类,它是文件和文件目录的抽象表示形式。

在创建 File 类对象的时候,需要指定路径,这样 File 对象就可以与硬盘上的文件或目录建立映射,通过操作 File 类对象来实现对文件或目录的操作。当然指定路径的文件或目录可能不存在,可以通过 File 对象的方法进行判断或创建文件。

使用 File 对象能新建、删除、重命名文件和目录,但不能访问文件内容本身,如果需要访问文件内容本身,则需要使用后面的输入/输出流。

下面演示一下 File 类的使用。

1 创建 File 对象

可以通过文件的绝对路径来创建文件对象,下面在 C 盘 Document 文件夹下创建一个 text.txt 的 File 对象:

File file = new File("C:\\Document\\test.txt");

也可以使用相对路径:

File file = new File("test.txt");

上面表示在当前工作目录下创建 text.txt 的 File 对象,在当前项目中,工作目录就是项目的根目录。

也可以通过指定父路径和当前文件文件的名称来创建:

File file = new File("C:\\Document", "test.txt");

关于绝对路径和相对路径

绝对路径是指从文件系统的根目录(在Windows中通常是某个驱动器,如C:\;在Unix或Linux中通常是/)开始,到目标文件或目录的完整路径。它不会依赖于当前工作目录的位置。

示例

  • 在Windows中:C:\Users\UserName\Documents\file.txt
  • 在Unix或Linux中:/home/username/documents/file.txt

相对路径是指从当前工作目录开始,到目标文件或目录的路径。它会依赖于当前工作目录的位置。

示例

  • 如果当前工作目录是C:\Users\UserName,那么相对路径Documents\file.txt 指向 C:\Users\UserName\Documents\file.txt
  • 如果当前工作目录是/home/username,那么相对路径documents/file.txt 指向 /home/username/documents/file.txt

2 常用操作

有了 File 对象,就可以进行下面的一些列操作了。

package com.doubibiji;

import java.io.File;
import java.io.IOException;

public class FileTest {
    public static void main(String[] args) throws IOException {
        // 在项目根目录下创建 test.txt 对象
        File file = new File("test.txt");
        // 创建文件
        file.createNewFile();

        // 判断文件是否存在
        System.out.println(file.exists());
        // 判断文件是否是目录
        System.out.println(file.isDirectory());
        // 判断是否是文件
        System.out.println(file.isFile());
        // 判断文件是否可读
        System.out.println(file.canRead());
        // 判断文件是否可写
        System.out.println(file.canWrite());
        // 判断是否是隐藏文件
        System.out.println(file.isHidden());
        // 获取文件的绝对路径
        System.out.println(file.getAbsolutePath());
        // 删除文件,这里屏蔽是因为上面创建了文件,这里又删除了,好像什么都没有发生,屏蔽是为了看到这个文件
        // file.delete();
    }
}

3 创建目录

在实际的开发中,我们会经常遇到这样的需求,判断某个路径是否存在,如果不存在就创建这个目录 。

下面使用代码实现:

public static void main(String[] args) {
    // 指定要创建的目录
    String filePath = "C:\\docs\\images";
    File file = new File(filePath);

    // 判断目录是否存在
    if (!file.exists()) {
        // 创建目录,会按照结构一层一层创建
        boolean result = file.mkdirs();

        if (result) {
            System.out.println("目录创建成功: " + filePath);
        } else {
            System.out.println("目录创建失败: " + filePath);
        }
    } else {
        System.out.println("目录已存在: " + filePath);
    }
}

5 文件过滤器

上面通过 listFiles() 方法列出目录下所有的文件,我们也可以在列出文件的时候,通过过滤器,列出想要的文件。

例如,下面列出目录下所有的 .jpg 文件

public static void main(String[] args) {
    File file = new File("C:\\docs\\images");

    if (file.isDirectory()) {
        // 获取目录下所有的文件
        File[] files = file.listFiles(new FileFilter() {
            @Override
            public boolean accept(File subFile) {
                return subFile.isFile() && subFile.getName().endsWith("jpg");
            }
        });

        // 获取到所有的jpg文件,就可以针对这些文件进行操作,例如下面删除这些文件
        for (File jpgFile : files) {
            System.out.println(jpgFile.delete());
        }
    } else {
        System.out.println("不是目录");
    }
}

7 删除目录下的所有文件

如果一个目录下有文件,是无法通过 file.delete() 来删除的。如果要删除一个目录,需要将这个目录下所有的文件和目录都删掉,然后才能删除该目录。这里就涉及到递归删除了,因为该文件夹下还可能有文件夹。

下面写了一个方法 deleteFile() ,可以用来删除文件或目录:

public class FileTest {

    public static void main(String[] args) {
        File directoryToDelete = new File("docs/images");
        // 删除目录
        deleteFile(directoryToDelete);
    }

    /**
     * 删除文件或目录
     */
    public static void deleteFile(File file) {
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            if (files != null) {
                for (File subFile : files) {
                    deleteFile(subFile); // 递归删除子文件和子目录
                }
            }
        }

        // 在此点,目录应该是空的(或本身就不存在),可以安全删除
        boolean success = file.delete();
        if (success) {
            System.out.println("文件已删除: " + file.getAbsolutePath());
        } else {
            System.out.println("删除文件失败: " + file.getAbsolutePath());
        }
    }
}

在上面的 deleteFile 方法中,使用了递归删除。

8 File.separator

File.separator 是 Java 中表示系统默认文件目录分隔符的静态变量

在 Windows 系统中,文件目录分隔符为 \,而在 Linux 和 UNIX 系统中,文件目录分隔符为 / 。使用 File.separator 可以确保在任何系统下都能正确表示文件路径,从而避免了因为系统差异导致的路径错误问题。

例如,要在 temp 目录下建立一个名为 test.txt 的文件,可以这样做:

File myFile = new File("C:" + File.separator + "temp" + File.separator + "test.txt");

1

这样,无论是在Windows系统还是Linux系统,都能正确地创建文件。在编程时,应尽量使用这些与系统相关的字段,以确保代码的跨平台兼容性。

9 常用方法

下面列出 File 对象常用的一些方法:

方法含义
file.createNewFile();创建文件,创建成功返回true,如果存在就不创建了,返回false
file.mkdir();创建文件夹,创建成功返回true,如果存在就不创建了,返回false
file.mkdirs("cc/dd");创建多级目录,创建成功返回true,如果存在就不创建了,返回false
file.renameTo();如果路径相同,就是改名,如果路径不同,就是改名并剪切
file.delete();删除,Java中删除不走回收站,要删除一个文件夹,请注意该文件夹内不能包含文件或文件夹
file.setReadable(false);设置文件不可读
file.canRead();windows系统认为所有的文件都是可读的,可读表示是否可以使用IO流读取
file.getAbsolutePath();获取绝对路径
file.getPath();获取构造方法中传入的路径,如果传给构造方法的是绝对路径就返回的是绝对路径,如果传递给的是相对路径就返回的是相对路径
file.list();获取文件夹下的所有文件或文件夹的名称
file.listFiles();获取文件夹下的所有文件或文件夹的File对象

IO流

上面在使用 File 对象来进行操作的时候,是无法对文件的内容进行操作的,如果要对文件进行读写,就需要用到 IO 流。

Java对数据的操作是通过流的方式,用于操作流的类都在IO包中;IO流用来处理设备之间的数据传输的,为 数据源 和 目的地 建立一个输送通道,也就是从哪里读取数据和将数据写到哪里;

流按照流向分为两种:

输入流

程序从输入流读取数据源数据。数据源包括外界(键盘、文件、网络…),即是将数据源的数据读入到程序的通信通道。

输出流

程序向输出流写入数据。将程序中的数据输出到外界(显示器、打印机、文件、网络…)的通信通道;

流按照类型分为两种:

字节流

数据流中最小的数据单元是字节,字节流可以操作任何数据,因为在计算机中任何数据都是以字节的形式存储的;

字符流

数据流中最小的数据单元是字符,字符流只能操作纯字符数据, Java中的字符是Unicode编码,一个字符占用两个字节。

字节流可以操作任何数据了,为什么还需要字符流?

为了方便,可以使用不同的编码进行读取和写出;因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。

1 IO操作主要的类

1 File(文件特征与管理)

用于文件或者目录的描述信息,例如生成新目录,修改文件名,删除文件,判断文件所在路径等。

2 InputStream(二进制格式操作)

抽象类,基于字节的输入操作,是所有输入流的父类。定义了所有输入流都具有的共同特征。

3 OutputStream(二进制格式操作)

抽象类。基于字节的输出操作。是所有输出流的父类。定义了所有输出流都具有的共同特征。

InputStream和OutputStream是字节流的最顶层的抽象父类,需要使用其子类来实现功能。

4 Reader(文本格式操作)

抽象类,基于字符的输入操作。

5 Writer(文本格式操作)

抽象类,基于字符的输出操作。

Reader和Writer是字符流的最顶层的抽象父类,需要使用其子类来实现功能。

通过名称就可以分辨出是字节流还是字符流,以Stream还是Reader/Writer结尾。

6 RandomAccessFile(随机文件操作)

一个独立的类,直接继承至Object,它的功能丰富,可以从文件的任意位置进行存取(输入输出)操作。

 字节流

1 FileInputStream

FileInputStream 用于读取文件数据。

1 读取一个字节

有一个 xxx.txt 文件,其中的内容为:abc

FileInputStream fis = new FileInputStream("xxx.txt");
int x = fis.read();
System.out.println(x);
fis.close();

fis.read() 方法会读取文件的一个字节,复制给 int x,最终打印的结果是 97

数据存储在硬盘上是以二进制保存的,字母 a 对应的二进制数据以十进制表示就是 97,可以查看ASCII码表查看。

fis.read() 每读取一次,指针会向后移动,读取下一个字节。当读到文件的末尾,没有数据时,会返回 -1,表示文件结束。

2 一个一个读取所有字节

使用一个循环,使用 read() 方法一直读取,直到读取到的内容是 -1

FileInputStream fis = new FileInputStream("xxx.txt");
int b;
while((b = fis.read()) != -1) {
    System.out.println(b);
}
fis.close();

read() 方法读取的是一个字节,为什么返回是 int,而不是 byte ?

因为字节输入流可以操作任意文件,比如图片音频等,这些文件底层都是以二进制形式存储的,如果每次都读取返回 byte,有时候可能在中间的时候遇到 11111111,那么这个 11111111 是byte类型的 -1,程序是遇到 -1 就会停止不读了,后面的数据就读取不到了,所以在读取的时候用int类型接收,如果 11111111 会在前面补上 24 个 0 凑足int的4个字节,那么 byte 类型的 -1 就变成int类型的 255了,这样就可以保证整个数据读完,而结束标记的 -1 就是int类型。

2 FileOutputStream

FileOutputStream 用于写入数据到文件。FileInputStream,FileOutputStream只是读和写的区别。

1 写入一个字节
FileOutputStream fos = new FileOutputStream("yyy.txt");    //创建字节输出流对象,如果没有就自动创建文件
fos.write(97);
fos.write(98);
fos.write(99);
fos.close();

write() 方法会写出一个字节,虽然写出的是 int 数,但是到文件上是一个字节,会自动去除 int 前三个 8位。所以最终 yyy.txt 文件的内容为:abc

上面在写入的时候,是会覆盖原来文件中的内容,如果想在原来的内容后面追加内容,可以在创建 FileOutputStream 指定第二个参数:

new FileOutputStream("yyy.txt",  true);    //第二个参数表示追加

3 IO流功能的核心代码

下面使用 FileInputStream 和 FileOutputStream 来完成文件的复制。

文件的复制也就是读取一个文件的内容,写入到另一个文件。

复制文件功能的样例:

//创建输入流对象
FileInputStream fis = new FileInputStream("aaa.jpg");
//创建输出流对象
FileOutputStream fos = new FileOutputStream("bbb.jpg");

int b;
//不断的读取每一个字节
while ((b = fis.read()) != -1) {
    //将每一个字节写出
    fos.write(b);
}

//关闭流释放资源
fis.close();
fos.close();

#4 缓存数组

上面的代码都是一个字节一个字节的读取和写出,效率非常低,如何才能提高效率呢?可以使用一个字节数组,一次读取多个字节,一次写出多个字节。如下:

xxx.txt 的内容为:abc

// 创建输入流对象
FileInputStream fis = new FileInputStream("xxx.txt");

// 设置一个长度为2的缓存数组
byte[] arr = new byte[2];
// 读取两个字节
int a = fis.read(arr);
System.out.println("a:" + a);

// 查看一下读取的内容
for (byte b : arr) {
    System.out.println(b);
}

System.out.println("-----------");

// 再次读取两个字节
int c = fis.read(arr);
System.out.println("c:" + c);

// 查看一下读取的内容
for (byte b : arr) {
    System.out.println(b);
}

//关闭流释放资源
fis.close();

read(byte[]) 方法会读取 byte[] 长度的字节到该字节数组中,同时返回读取的长度。

xxx.txt 的内容为 abc ,为何第二次读取却读取到了99和98?因为第一次读取到两个字节为97和98,第二次读取的时候,将第三个字节读取覆盖数组的第一个位置,后面没有读取的内容了,但数组后面的内容是之前读取到的内容,并没有被修改。所以在写出数据的时候一定要注意,通过使用 read(byte[]) 方法的返回值,即读取的长度来控制写入。

5 完整的输入输出流

通过使用一个数组来读取,可以提高读取的效率,下面循环来读取就可以了。

完整的文件输入输出流代码如下:

//创建输入流对象
FileInputStream fis = new FileInputStream("xxx.txt");
//创建输出流对象
FileOutputStream fos = new FileOutputStream("yyy.txt");

byte[] arr = new byte[2];
int len;
while ((len = fis.read(arr)) != -1) {
  	//控制写入长度
    fos.write(arr, 0, len);
}

//关闭流释放资源
fis.close();
fos.close();

fis.read(arr) 返回读取长度,如果等于 -1 表示读取结束,写出的时候,将数组从第0个写出到len个长度。

数组的尺寸一般定义为1024的整数倍1024 * n。

1 使用Buffered读取写入

使用方法如下:

使用 BufferedInputStream 对 FileInputStream 进行一层包装即可。

//创建输入流对象,关联文件
FileInputStream fis = new FileInputStream("xxx.txt");
//创建输出流对象,指定输入对象
FileOutputStream fos = new FileOutputStream("yyy.txt");

BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream bos = new BufferedOutputStream(fos);

//定义的数组的意思是每次读取1024个字节到缓冲区
byte[] arr = new byte[1024];
int len;
while ((len = bis.read(arr)) != -1) {
    bos.write(arr, 0, len);
}

//只需要关闭包装后的流对象
bis.close();
bos.close();

在关闭资源的时候,只需要关闭包装后的流对象即可,因为可以这样创建BufferedInputStream:

BufferedInputStream bis = new BufferedInputStream(new FileInputStream("xxx.txt"));

7 flush方法

在写入文件的时候,会将文件的内容写入到缓冲区,如果想将缓冲区的内容立刻写入到文件,可以调用输出流的 flush() 方法。

flush 和 close 方法的区别:

close()方法具备刷新的功能,在关闭流之前,会先刷新一次缓冲区,将缓冲区的字节全都刷新到文件上,然后在关闭。 flush() 方法具备刷新缓冲区,将缓冲区数据写到文件上的功能,刷新完成之后可以继续写。如果想将数据写出,就需要 flush 缓冲区。

8 流的标准异常处理

我们使用 IO 流的时候,会有一些异常,在整个处理的过程中,需要考虑资源的关闭,如果不及时关闭资源,会造成资源泄露,进而引发性能问题或内存溢出等错误。

标准的流的异常处理如下:

public static void main(String[] args) throws IOException {
    FileInputStream fis = null;
    FileOutputStream fos = null;
  
    try {
        fis = new FileInputStream("xxx.txt");
        fos = new FileOutputStream("yyy.txt");

        byte[] arr = new byte[1024];
        int len;
        while ((len = fis.read(arr)) != -1) {
            fos.write(arr, 0, len);
        }
    } catch (IOException e) {  
        // 处理读写文件时抛出的异常  
        e.printStackTrace();  
    } finally {  
        try {  
            if (fis != null) {  
                fis.close();  
            }  
        } catch (IOException e) {  
            // 处理fis.close()抛出的异常  
            e.printStackTrace();  
        }  
      
        try {  
            if (fos != null) {  
                fos.close();  
            }  
        } catch (IOException e) {  
            // 处理fos.close()抛出的异常  
            e.printStackTrace();  
        }  
    }
}

try finally嵌套,能关闭一个资源就关闭一个资源,上面是1.6版本的写法。

Java1.7版本对输入输出流进行了优化,提供了自动关闭的功能

try (
        FileInputStream fis = new FileInputStream("xxx.txt");
        FileOutputStream fos = new FileOutputStream("yyy.txt");
        )
{
    byte[] arr = new byte[1024];
    int len;
    while ((len = fis.read(arr)) != -1) {
        fos.write(arr, 0, len);
    }

}

代码在执行完大括号中的内容后,会自动关闭小括号中的对象。

因为FileInputStream和FileOutputStream实现了AutoCloseable接口,所以在小括号中是无法创建我们自己编写的对象的,除非我们自己编写的对象也实现了AutoCloseable接口:

static class MyClass implements AutoCloseable {
    @Override
    public void close() {
        System.out.println("我关闭了");
    }
}

try (
        FileInputStream fis = new FileInputStream("xxx.txt");
        FileOutputStream fos = new FileOutputStream("yyy.txt");
        MyClass myClass = new MyClass();
        )
{
...
}

InputStream in = JdbcPool.class.getClassLoader().getResourceAsStream("db.properties");
Properties prop = new Properties();
try {
    prop.load(in);
    String driver = prop.getProperty("driver");
    String url = prop.getProperty("url");
    String username = prop.getProperty("username");
    String password = prop.getProperty("password");
} catch (Exception e) {
    e.printStackTrace();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值