文件和目录

前言

本章讨论文件属性和文件系统内容。除了上一章讨论的普通文件,Linux的文件概念还包括:目录、设备等。在Linux系统中,文件的种类包括:普通文件、目录、符号链接、块设备、字符设备、管道、套接字。

本章讨论的主要内容为普通文件、目录和符号链接。它们的公共特点是,真实的保存在了硬盘中,而其它类型的文件是内核产生的文件,在硬盘中并不存在。

文件属性

通过stat函数或者stat命令可以获得文件属性。

文件属性 解释
dev_t st_dev 设备号
ino_t st_ino inode编号
mode_t st_mode 访问权限相关
nlink_t st_nlink 硬链接数量
uid_t st_uid 拥有该文件的用户
gid_t st_gid 拥有该文件的组
dev_t st_rdev 设备号
off_t st_size 文件尺寸
blksize_t st_blksize 文件系统的IO尺寸
blkcnt_t st_blocks 占用的block数量,一个block为512字节
time_t st_atime 最后访问时间
time_t st_mtime 最后修改时间
time_t st_ctime 最后文件状态修改时间
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> int main()
{
struct stat buf;
int ret = stat(".", &buf);
if(ret < 0)
{
perror("stat");
return 0;
} if(S_ISREG(buf.st_mode))
{
printf("this is regular file\n");
}
else if(S_ISDIR(buf.st_mode))
{
printf("this is dir\n");
} // 测试拥有该文件的账户是否有读权限
if(S_IRUSR & buf.st_mode)
{
printf("user can read\n");
} open("a.txt", O_CREAT|O_RDWR, 0777); // access("./a.out", R_OK|W_OK|X_OK); printf("file size is %d\n", (int)buf.st_size);
getchar();
return 0;
}

3.3 文件类型

在前言中,提到文件类型包括七种,在stat结构题中,保存了文件的文件类型属性,它的文件类型属性保存在st_mode中。但是七种类型,只需要3位即可,而st_mode是一个整数,因此它还保存其它内容,如果需要判断一个文件属于何种类型,需要一些宏的帮助。


int main()
{
  struct stat buf;
  stat("a.txt", &stat);
  if(S_ISREG(buf.st_mode))
  {
    printf("%s\n", "这是普通文件");
  }
}

文件类型属性是只读的属性,无法修改。

3.4 用户和组

Linux是一个多用户操作系统,因此每个文件都有属性,记录着这个文件属于哪个用户/组。
用户/组信息可以被修改,可以通过chown来修改文件所属的用户和组信息。
修改文件所属用户和组,需要root权限。
新文件所属用户和组,是创建该文件的进程所属用户和组。

  • 实际账户和有效账户

账户 解释
实际账户 登陆系统时的账户
有效账户 决定进程的访问资源的账户

3.5 文件访问权限

文件使用了9个位来表示访问权限,和文件类型一起,保存在st_mode中。此9位分成3组,每组3个位,分别表示读/写/执行权限,而三个组分别表示拥有该文件的账户,拥有该文件的组,其它用户组的权限。如果对应位是1,表示有权限,如果是0表示没有权限。

1 1 1 1 0 1 1 0 1

文件访问权限经常用8进制来表示,比如上表的权限位可以表示为0755,意思是拥有它的账户对这个文件有读/写/执行权限,而拥有它的组有读/执行权限,其它账户对它有读/执行权限。

Linux提供一些宏,来测试文件的权限位

  • 可以通过access函数来测试程序是否有访问某文件的权限。

  • 创建文件时,可以指定文件的访问权限位,但是会收到umask位影响。

  • 可以通过chmod来修改文件的权限位

3.6 其它权限位

3.6.1 SUID

只能对文件设置,如果文件设置了该位,那么该文件被运行时,对应的进程的权限,不是运行该程序账户的权限,而是拥有该用户的权限。

在对文件未设置SUID的情况下:

如果对文件设置了SUID,那么:

可以通过chmod u+s或者chmod u-s来设置获取去除SUID。
设置SUID可以让一个普通账户拥有它不该有的权限,容易产生安全漏洞。

3.6.2 SGID

可以对文件和目录设置,如果对文件设置,那么它的作用类似SUID,不过影响的是组。

如果对目录设置,那么拷贝到该目录下的文件都会被置位,除非拷贝是带-p参数。 在Ubuntu下测试并不如此。
在Ubuntu下设置了目录的SGID之后,在那个目录下创建的文件,拥有者是有效账户,而拥有组是该目录的拥有组。

命令:
chmod g+s
chmod g-s

3.6.3 StickyBit

可以对文件或者目录设置,如果对文件设置,那么当这个文件运行并退出后,系统依旧保留该文件对应的映象,这样这个程序再次运行时,就不需要加载再加载了。这个属性的作用并不大,因为它占用了内存。

如果对目录设置,那么表示在该目录下,账户只能删除和修改它自己创建的文件,对于其它账户创建的文件,它不能修改和删除。这个位作用比较大,在一些公共目录,往往有这个属性,比如/tmp

命令:
chmod o+t
chmod o-t

总结:

设置对象 设置方法 查看 效果
SUID 文件 chmod u+s 如果用户执行权限位为s或者S,则表示SUID有设置 当该文件被执行时,进程所拥有的权限是拥有该文件的账户权限
SUID 目录 不可设置    
SGID 文件 chmod g+s 如果组执行权限位为s或者S,则表示GUID有设置 当执行该文件时,进程所属组是该拥有该文件的组
SGID 目录 chmod g+s 同上 在该目录中创建文件时,该文件的所属组是目录的所属组
StickyBit 文件 chmod o+t 如果其他执行权限位为t或者T,那么该文件有设置StickyBit 执行该文件并退出后,系统保留该文件占用的一些内存,以便加快下一次的加载运行
StickyBit 目录 chmod o+t 同上 账户只能修改和删除该目录下属于该账户的文件,不能修改该目录下其他账户创建的文件

3.7 文件长度

st_size保存文件的长度,write函数会修改该属性,也可以通过truncate修改文件大小,truncate可以扩大文件或者缩小文件,缩小文件时,文件内容会被删减。

文件大小可以通过lswc -cstat命令获取。
也可以通过fseekftell函数配合获取,或者直接通过stat函数获取文件长度。

3.8 文件系统

3.8.1 文件管理

文件系统描述文件在硬盘中的组织,保存在硬盘中的文件只有普通文件、目录、软链接。

为了更加方便的管理持久性文件存储,操作系统一般对硬盘进行有规划的管理,规划包括:

  • 分区

  • 格式化

文件系统指一个分区内,文件存储的组织方式。

在Linux下,通过mount命令将分区挂载到虚拟文件系统。

3.8.2 inode

一个硬盘分区,被格式化之后,可以认为硬盘被划分成两部分:管理数据和数据。管理数据部分保存着这个分区的分区信息,以及inode表。

inode保存文件的属性信息,stat命令能看到的信息,大部分都是保存在inode里的,一个inode占用128或者256字节,这个依赖具体的文件系统,每当在硬盘上创建一个文件/目录时,系统为这个文件/目录分配一个inode。值得注意的是,文件名,不存在inode中,而是存在文件所在目录的文件内容部分。

3.8.3 数据块

数据部分被简单的、按照等大尺寸的划分成n块,一般每块数据块的尺寸为1024-4096,由具体文件系统决定。

3.8.4 文件

当创建一个文件时,系统为该文件分配一个inode。如果往该文件写数据,那么系统为该文件分配数据块,inode会记录这个数据块位置,当一个数据块不够用时,系统会继续为它分配数据块。

3.8.5 目录

当创建一个目录时,系统为该目录分配一个inode,同时分配一个数据块,并且在该数据块中,记录文件...对应的inode。

如果在该目录下创建文件newfile,那么参考上一节内容,会为该文件创建inode,最后将newfile文件名和它的inode,作为一条记录,保存在目录的数据块中。

如果一个inode被别人引用,那么它的引用计数器会加1。

3.8.6 路径和寻址

Linux系统采用以/划分的路径字符串来寻址文件。

比如命令mkdir testdir,寻址和操作过程如下图:


思考:为什么mv命令很快,而cp命令很慢,rename如何实现的

补充:分区

查看磁盘信息

sudo fdisk -l

磁盘名字 sda sdb ..
分区名字 sda1 sda2 ...
分区

sudo fdisk /dev/sdb

n 创建新分区
p 输出分区信息
w 保存分区信息并退出

分区和挂载

sudo mkfs.ext4 /dev/sdb1
sudo mount /dev/sdb1 xxyy

挂载成功之后,对xxyy目录的读写,其实是在/dev/sdb1文件系统中。

开机自动挂载
通过mount挂载的目录是临时的。如果希望开酒就挂载,那么可以将挂载命令写入到/etc/profile。或者修改/etc/fstab文件,/etc/fstab描述了开机需要挂载的文件系统信息。

去除挂载
通过手动umount去除挂载。

3.8.7 硬链接和软链接

硬链接不占用inode,只占用目录项。
软链接占用inode。

创建链接命令ln,硬链接只将对应的inode在目录总增加一个名字,并且将inode的引用计数器+1。

为了可以跨文件系统和对目录进行链接,创建了软链接这种方式。ln -s

// file --> file2
int main()
{
    // get file2
    struct stat buf;
    stat("file", &buf);
 
    // get 链接文件file的信息
    struct stat buf2;
    lstat("file", &buf2);
 
    // 如果lstat的参数所指文件不是链接文件
    // 那么它的效果和stat一样
    struct stat buf3;
    lstat("file2", &buf3)
}
读取symlink内容使用readlink命令。
删除软链接不会删除软链接指向的文件。

思考:为什么硬链接不能跨文件系统,而且不能对目录进行硬链接

3.8.8 虚拟文件系统VFS

内存无法加载硬盘所有内容,因为一般内存比硬盘小,但是在Linux内核中,维护了一个虚拟文件系统,将硬盘的目录结构映射到内存中。这个映射一般只包含已经被打开的文件。


3.9 文件删除

使用unlink命令和函数可以删除一个文件。
如果此时文件已经打开,那么该文件也可以被unlink,但是删除操作不会立即执行,而会被保留到文件关闭时执行。

unlink 删除文件,如果是链接,就删除链接,如果不是链接就删除文件。
rmdir 只能删除空目录
rm 会判断参数类型,如果是文件那么调用unlink,如果是目录调用rmdir
如果要删除非空目录,要使用rm -r,-r选项先删除目录中的文件,再调用rmdir。
int rm(const char* path);
{
    // 怎么遍历目录
}

3.10 文件时间

对文件的访问,会导致文件时间发生变化。系统会自动记录用户对文件的操作的时间戳,以便将来可以查询文件修改时间。

如果需要故意修改,那么可以通过utime函数,修改文件的访问时间和修改时间。

touch命令也可以将文件的时间修改为当前时间。touch命令的副作用是,如果参数所指文件不存在,那么创建一个空文件。

当用户进行大规模拷贝时,cp操作会修改文件的访问时间,如果想提高效率,可以使用-p选项,避免文件属性的修改,同时加快速度。

 
#include <sys/types.h>
#include <utime.h> int main()
{
struct utimbuf buf;
buf.actime = 0;
buf.modtime = 0;
utime("a.out", &buf);
}

利用utime来修改文件的访问时间和修改时间

#include "../h.h"
int main()
{
    struct utimbuf buf;
    buf.actime = 0;
    buf.modtime = 0;
    utime("testfile", &buf);
 
    struct timeval tv[2];
    tv[0].tv_sec = 100000;
    tv[0].tv_usec = 10000;
 
    tv[1].tv_sec = 100000;
    tv[1].tv_usec = 10000;
    utimes("testfile", tv);
}

3.11 目录操作

3.11.1 创建和删除目录

mkdirrmdir

3.11.2 遍历目录

opendirclosedirreaddirrewinddirtelldirseekdir

遍历目录

#include "../h.h"
 
int rm(const char* path)
{
    // 判断path是个文件还是目录
    // 如果是文件,直接unlink然后返回
    struct stat stat_buf;
    int ret = stat(path, &stat_buf);
    if(ret < 0)
    {
        perror("stat");
        return -1;
    }
    if(!S_ISDIR(stat_buf.st_mode))
    {
        unlink(path);
        return 0;
    }
 
    // 如果path是目录,遍历目录中的所有目录项
    char buf[1024];
    DIR* dir = opendir(path);
    if(dir == NULL)
        return -1;
 
    struct dirent* entry = readdir(dir);
    while(entry)
    {
        // 通过entry得到文件信息
        sprintf(buf, "%s/%s", path, entry->d_name);
        if(entry->d_type == DT_REG || entry->d_type == DT_LNK)
        {
            unlink(buf);
        }
        if(entry->d_type == DT_DIR)
        {
            // 忽略.和..目录
            if(strcmp(entry->d_name, ".") == 0
                    ||strcmp( entry->d_name, "..") == 0)
            {
                entry = readdir(dir);
                continue;
            }
            rm(buf);
        }
        entry = readdir(dir);
    }
 
    closedir(dir);
    rmdir(path);
    return 0;
}
 
int main(int argc, char* argv[])
{
    if(argc == 1)
    {
        printf("usage: %s [pathname]\n", argv[0]);
        return 0;
    }
    rm(argv[1]);
    return 0;   
}

seekdir和telldir

 
#include "../h.h"
 
int main()
{
    long loc;
    DIR* dir = opendir("testdir");
 
    // no
    // seekdir(dir, 2);
    //
    struct dirent* entry;
    while(1)
    {
        loc = telldir(dir);
        entry = readdir(dir);
        if(entry == NULL) break;
 
        if(strcmp(entry->d_name, "a") == 0)
        {
            // 记录文件a的位置
            break;
        }
    }
 
    seekdir(dir, loc);
 
    while(1)
    {
        entry = readdir(dir);
        if(entry == NULL)
            break;
        printf("loc is %d, entry->d_name=%s\n", (int)telldir(dir), entry->d_name);
    }
 
    // 将文件指针回到a的位置
//    seekdir(dir, loc);
}
#include <dirent.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h> int main(int argc, char* argv[])
{
DIR* dir = opendir(argv[1]);
struct dirent* entry; while(1)
{
entry = readdir(dir);
if(entry == NULL)
break; // linux下,.开头是隐藏文件
if(entry->d_name[0] == '.')
continue; printf("%s\n", entry->d_name);
} closedir(dir);
}

3.12 练习

3.12.1 实现文件拷贝,保留文件属性

#include "../h.h"
 
int main(int argc, char* argv[])
{
    if(argc != 3)
    {
        printf("usage: %s [srcfile] [dstfile]\n", argv[0]);
        return -1;
    }
 
    const char* filesrc = argv[1];
    const char* filedst = argv[2];
 
    FILE* fp_src = fopen(filesrc, "r");
    FILE* fp_dst = fopen(filedst, "w");
 
    char buf[4096];
    while(1)
    {
        int ret = fread(buf, 1, sizeof(buf), fp_src);
        if(ret <= 0)
            break;
        fwrite(buf, ret, 1, fp_dst);
    }
 
    fclose(fp_src);
    fclose(fp_dst);
 
 
    // 获取源文件属性
    struct stat src_stat;
    stat(filesrc, &src_stat);
 
    // 修改目标文件时间
    struct utimbuf timbuf;
    timbuf.actime = src_stat.st_atime;
    timbuf.modtime = src_stat.st_mtime;
    utime(filedst, &timbuf);
 
    // 修改权限
    chmod(filedst, src_stat.st_mode);
 
    // 修改所有者
    int ret = chown(filedst, src_stat.st_uid, src_stat.st_gid);
    if(ret < 0)
    {
        perror("chown");
    }
 
    return 0;
}

3.12.2 实现目录打包到文件,将文件解包成目录

 
#include "../h.h"
 
#include <map>
#include <string>
using namespace std;
 
map<ino_t, std::string> savedfiles;
 
void tarfile(const char* filename, FILE* fpOut)
{
    struct stat stat_buf;
    stat(filename, &stat_buf);
 
    // 检查这个文件是否已经保存过,是否是其他文件的硬链接
    std::string filesaved = savedfiles[stat_buf.st_ino];
    if(filesaved.size() != 0)
    {
        // 此ino之前已经存过了
        fprintf(fpOut, "h\n%s\n%s\n", filename, filesaved.c_str());
        return;
    }
 
    fprintf(fpOut, "f\n%s\n%lld\n", filename, (long long int)stat_buf.st_size);
 
    FILE* fpIn = fopen(filename, "r");
    char buf[4096];
    while(1)
    {
        int ret = fread(buf, 1, sizeof(buf), fpIn);
        if(ret <= 0)
            break;
        fwrite(buf, ret, 1, fpOut);
    }
    fclose(fpIn);
 //   savedfiles.insert(std::pair<ino_t, std::string>(stat_buf.st_ino, std::string(filename)));
    // 如果该文件不是别人的硬链接,那么将文件拷贝之后,在全局map中记录ino
    savedfiles[stat_buf.st_ino] = std::string(filename);
}
 
int tardir(const char* dirname, FILE* fpOut)
{
    char filepath[1024];
 
    // 写目录
    fprintf(fpOut, "d\n");
    fprintf(fpOut, "%s\n", dirname);
 
    DIR* dir = opendir(dirname);
    struct dirent* entry = readdir(dir);
    while(entry)
    {
        sprintf(filepath, "%s/%s", dirname, entry->d_name);
        // handle
        if(entry->d_type == DT_REG)
        {
            // write file
            tarfile(filepath, fpOut);
        }
        else if(entry->d_type == DT_DIR)
        {
            if(strcmp(entry->d_name, ".") == 0 ||
                    strcmp(entry->d_name, "..") == 0)
            {
                entry = readdir(dir);
                continue;
            }
 
            tardir(filepath, fpOut);
        }
        entry = readdir(dir);
    }
 
    closedir(dir);
}
 
int tar(const char* dirname, const char* outfile)
{
    FILE* fpOut = fopen(outfile, "w");
 
    fprintf(fpOut, "xgltar\n");
    fprintf(fpOut, "1.0\n");
 
    int ret = tardir(dirname, fpOut);
 
    fclose(fpOut);
    return ret;
}
 
 
#define line_buf_size 1024
char line_buf[line_buf_size];
#define get_line() fgets(buf, line_buf_size, fin)
 
int untar1(FILE* fin)
{
    char* buf = line_buf;
    if(get_line() == NULL)
        return -1;
 
    printf("now utar type=%s", buf);
 
    if(strcmp(buf, "d\n") == 0)
    {
        get_line();
        buf[strlen(buf)-1] = 0;
        mkdir(buf, 0777);
        printf("mkdir %s\n", buf);
    }
    else if(strcmp(buf, "f\n") == 0)
    {
        get_line();
        buf[strlen(buf)-1] = 0; // filename
        FILE* out = fopen(buf, "w");
        printf("create file %s\n", buf);
 
        get_line();
        long long int len = atoll(buf); // 1987\n
        printf("filelen %s\n", buf);
 
        while(len > 0)
        {
            // 避免粘包问题
            int readlen = len < line_buf_size ? len : line_buf_size;
            int ret = fread(buf, 1, readlen, fin);
            fwrite(buf, 1, ret, out);
            len -= ret;
        }
 
        fclose(out);
    }
    else if(strcmp(buf, "h\n") == 0)
    {
        get_line();
        buf[strlen(buf)-1] = 0; // filename new
        std::string new_path(buf);
 
        get_line();
        buf[strlen(buf)-1] = 0; // hardline filename old
 
        link(buf, new_path.c_str());
    }
 
    return 0;
}
 
int untar(const char* tarfile)
{
    char* buf = line_buf;
 
    FILE* fin = fopen(tarfile, "r");
    //fgets(buf, line_buf_size, fin);
    get_line();
    if(strcmp(buf, "xgltar\n") != 0)
    {
        printf("unknown file format\n");
        return -1;
    }
 
    get_line();
    if(strcmp(buf, "1.0\n") == 0)
    {
        while(1)
        {
            int ret = untar1(fin);
            if(ret != 0)
                break;
        }
 
    }
    else
    {
        printf("unknown version\n");
        return -1;
    }
    return 0;
}
 
 
// ./mytar -c dir tarfile.xgl
// ./mytar -u tarfile.xgl
int main(int argc, char* argv[])
{
    if(argc == 1)
    {
        printf("usage: \n\t%s -c [dir] [tarfile]\n\t%s -u [tarfile]\n", argv[0], argv[0]);
        return -1;
    }    
 
    const char* option = argv[1];
    if(strcmp(option, "-c") == 0)
    {
        const char* dirname = argv[2];
        const char* outfile = argv[3];
        return tar(dirname, outfile);
    }
    else if(strcmp(option, "-u") == 0)
    {
        const char* tarfile = argv[2];
        return untar(tarfile);
    }
 
    printf("option error\n");
    return -1;
}

3.13 函数和命令

3.13.1 函数

stat/lstat:查看文件属性
chmod:修改文件权限
chown:修改文件的所有者
utime:修改文件时间
unlink:删除文件
link:创建硬链接
symlink:创建软链接
rmdir:删除空目录
mkdir:创建空目录
opendir:打开目录
closedir:关闭目录
readdir:读取一个目录项,并且将目录项指针移到下一项
seekdir:修改目录项指针
rewainddir:重置目录项指针
telldir:获得当前目录向指针
判断权限位宏 S_IRUSR(stat.st_mode)
判断文件类型宏S_ISDIR(stat.st_mode)

3.13.2 命令

stat:查看文件属性
chmod:修改文件权限
chown
unlink:删除文件(不会跟随)
ln:创建链接
mkdir
rmdir
rm
cp
dd:拷贝数据(可以拷贝文件,也拷贝块设备)
wc:计算文件内容的行数、单词数、字节数
which:查找非内置的命令位置
fdisk:查看磁盘信息、分区
mkfs:在分区中创建文件系统(ext2,ext3,ext4, fat32, ntfs, xfs,nfs)
mount:挂载
umount:取消挂载

Linux基础 文件和目录的更多相关文章

  1. Linux基础--文件与目录管理

    1.目录与路径 1)特殊目录 .   代表此层目录 ..  代表上一层目录 -   代表前一个工作目录 ~   代表『目前使用者身份』所在的家目录 ~account   代表account这个使用者的 ...

  2. (五)Linux之文件与目录管理以及文本处理

    Linux之文件与目录管理 目录 Linux之文件与目录管理 前言 绝对路径与相对路径说明: 一.目录常用命令 常用处理目录的命令: 切换目录 cd 显示当前路径 pwd 查看目录下文件 ls 创建目 ...

  3. [转]Linux中文件权限目录权限的意义及权限对文件目录的意义

    转自:http://www.jb51.net/article/77458.htm linux中目录与文件权限的意义 一.文件权限的意义 r:可以读这个文件的具体内容: w:可以编辑这个文件的内容,包括 ...

  4. Linux之文件、目录

    Linux之文件.目录 文件权限 User.Group.Others 在Linux中,任何一个文件都具有这三种身份的个别权限,三者的区别是 User: 指每一个单独的用户,例如member1,memb ...

  5. Linux命令——文件和目录管理

    Linux命令--文件和目录管理 基本命令 命令ls 作用:显示目录下的文件和文件夹 说明:默认显示当前目录,可跟路径参数 参数:-a,显示隐藏目录 参数:-l,显示文件权限 参数:-d,显示文件最后 ...

  6. tar---打包,解压缩linux的文件和目录

    tar命令可以为linux的文件和目录创建档案.利用tar,可以为某一特定文件创建档案(备份文件),也可以在档案中改变文件,或者向档案中加入新的文件.tar最初被用来在磁带上创建档案,现在,用户可以在 ...

  7. Linux 基础-文件权限与属性

    一,文件类型 1.1,概述 1.2,正规文件(regular file) 1.3,目录(directory) 1.4,链接文件(link) 1.5,设备与装置文件(device) 1.6,资料接口文件 ...

  8. Linux改变文件或目录的访问权限命令

    使用  ll  或  ls -l 指令时 第一列会显示出目录下文件的权限 例如∶ -rw-r-r- 横线代表空许可.r代表只读,w代表写,x代表可执行.注意这里共有10个位置.第一个字符指定了文件类型 ...

  9. linux命令——scp 两台linux机器间文件或目录传输

    不同的Linux之间copy文件常用有3种方法: 第一种:ftp,也就是其中一台Linux安装ftpServer,这样可以另外一台使用ftp的client程序来进行文件的copy. 第二种:采用sam ...

随机推荐

  1. Python(一)转义字符及操作符

    转义字符 描述 \(在行尾时) 续航符 \\ 反斜杠符号 \' 单引号 \'' 双引号 \a 响铃 \b 退格(Backspace) \e 转义 \000 空 \n 转行 \v 纵向制表符 \t 横向 ...

  2. Java问题之超过数值表示范围(例如64位)结果是什么 (阶乘)

    关于老师在课上所提及的这个问题 我做了验证 截图如下 只是一个简单的计算阶乘的代码 在运行时得到了如下结果 可以看到,对于部分数字如果超出范围会从64位处自动截断,而这时由于是二进制表示,首位默认是符 ...

  3. 重写 hashcode()真有那么简单嘛?

    万万没想到一个 hashcode() 方法,既然会引出一堆的知识盲区,简直了. 起因: 老八股:为什么重写Equals方法要重写HashCode方法. 大声告诉我为什么,闭着眼睛先把答案背出来,啥?这 ...

  4. jsp页面重定向后地址栏controller名重复而导致报404错误

    今天做ssm项目时遇到了这种错误 看看代码: 无关代码省略... 22 <body> 23 <div id="container"> 24 <ifra ...

  5. hyperf-搭建初始化

    官方文档* https://hyperf.wiki/2.0/#/README 初步搭建1. 安装项目 composer create-project hyperf/hyperf-skeleton 2. ...

  6. JavaScript中的代码执行顺序

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> </head&g ...

  7. 2022最新版超详细的Maven下载配置教程、IDEA中集成maven(包含图解过程)、以及导入项目时jar包下载不成功的问题解决

    文章目录 1.maven下载 2.maven环境变量的配置 3.查看maven是否配置成功 4.配置文件的修改 5.IDEA集成maven 6.导入项目时jar包下载不成功的问题解决 maven教程: ...

  8. vulnhub靶场之THALES: 1

    准备: 攻击机:虚拟机kali.本机win10. 靶机:THALES: 1,网段地址我这里设置的桥接,所以与本机电脑在同一网段,下载地址:https://download.vulnhub.com/th ...

  9. 第2-1-5章 docker安装MinIO实现文件存储服务-springboot整合minio-minio全网最全的资料

    目录 1. MinIO介绍 2. MinIO应用场景 2.1 单主机单硬盘模式 2.2 单主机多硬盘模式 2.3 多主机多硬盘分布式 3. MinIO特点 4. 存储机制 5. docker安装Min ...

  10. JUC学习笔记——共享模型之内存

    JUC学习笔记--共享模型之内存 在本系列内容中我们会对JUC做一个系统的学习,本片将会介绍JUC的内存部分 我们会分为以下几部分进行介绍: Java内存模型 可见性 模式之两阶段终止 模式之Balk ...