PHP 文件系统

在本文中我们介绍了 PHP 中的文件系统函数,我们处理文件和目录,确定文件许可权和可用磁盘空间,以及读写文件。 对于我们的示例,我们使用 PHP CLI

PHP 具有用于处理文件和目录的丰富函数集, PHP 包含低级和高级文件系统函数。 fopen()函数是一个低级函数的示例。 它是类似 C 函数的薄包装,file()函数是高级 PHP 文件系统函数的示例。

文件大小和类型

filesize()函数返回给定文件的大小。 大小以字节为单位指定。

get_filesize.php

<?php

filename = "fruits.txt";fsize = filesize(filename);

echo "The file size is:fsize bytes\n";

?>

在示例中,我们确定fruits.txt文件的大小。 该文件位于当前工作目录中,即与 PHP 脚本位于同一目录中。

$ php get_filesize.php 
The file size is: 40 bytes

fruits.txt文件的大小为 40 个字节。

filetype()函数获取文件的类型。 可能的返回值是:fifochardirblocklinkfilesocketunknown

file_types.php

<?php

echo filetype("myfile") . PHP_EOL;
echo filetype(".") . PHP_EOL;
echo filetype("/dev/tty1") . PHP_EOL;
echo filetype("/var/run/cups/cups.sock") . PHP_EOL;

?>

该脚本确定四个文件的类型。

$ php file_types.php 
file
dir
char
socket

这四个文件是常规文件,目录,字符设备和套接字。

文件是否存在

我们可能想使用一个不存在的文件,这可能发生。 file_exists()函数可用于防止这种情况。

file_existence.php

<?php

if (argc != 2) {

    exit("Usage: file_existence.php filename\n");
}filename = argv[1];r = file_exists(filename);

if (!r) {

    exit("Cannot determine the size of the file; the file does not exist\n");
}

fsize = filesize(filename);

echo "The file size is: $fsize bytes\n";

?>

该脚本在计算给定文件的大小之前会检查其是否存在。

if ($argc != 2) {

    exit("Usage: file_existence.php filename\n");
}

$argc是一个特殊变量,其中包含传递给脚本的参数数量。 我们需要两个参数:一个脚本名称和另一个作为参数传递的文件名。

$filename = $argv[1];

$argv是传递给脚本的参数数组。 我们得到第二个要素。

$r = file_exists($filename);

if (!$r) {

    exit("Cannot determine the size of the file; the file does not exist\n");
}

我们使用file_exists()函数检查文件是否存在。 如果它不存在,我们将以一条消息终止脚本。

$ php file_existence.php fruits.txt 
The file size is: 40 bytes

这是file_existence.php脚本的示例输出。

在下面的示例中,我们创建一个新文件,将其删除,然后检查其是否存在。 touch()函数设置文件的访问和修改时间。 如果该文件不存在,则会创建它。 unlink()函数删除文件。

file_existence2.php

<?php

filename = "newfile.txt";

if (file_exists(filename)) {

    echo "The file filename exists\n";

} else {

    echo "The filefilename does not exist\n";

    r = touch(filename);

    if (!r) {

        exit("Failed to touchfilename file\n");
    } else {

        echo "The file filename has been created\n";
    }
}r = unlink(filename);

if (r) {

    echo "The file filename was deleted\n";
} else {

    exit("Failed to deletefilename file\n");
}

if (file_exists(filename)) {

    echo "The filefilename exists\n";
} else {

    echo "The file $filename does not exist\n";
}

?>

在代码示例中,我们利用了所有三个函数:file_exists()touch()unlink()

$r = touch($filename);

touch()函数用于创建一个名为newfile.txt的新文件。

if (!r) {

    exit("Failed to touchfilename file\n");
} else {

    echo "The file $filename has been created\n";
}

如果touch()函数失败,则会打印一条错误消息。 许多 PHP 函数在失败时会返回false值。

$r = unlink($filename);

unlink()函数删除文件。

$ php file_existence2.php 
The file newfile.txt does not exist
The file newfile.txt has been created
The file newfile.txt was deleted
The file newfile.txt does not exist

这是file_existence2.php的输出。

复制和重命名文件

copy()函数复制文件,rename()重命名文件。 如果目标文件已经存在,它将被覆盖。

copy_file.php

<?php

r = copy("myfile.txt", "myfile2.txt");

if (r) {

    echo "Successfully copied file\n";
} else {

    exit("Failed to copy file\n");
}

?>

该脚本将复制文件。

rename_file.php

<?php

r = rename("myfile2.txt", "myfile_back.txt");

if (r) {

    echo "Successfully renamed file\n";
} else {

    exit("Failed to rename file\n");
}

?>

在此脚本中,我们使用rename()函数将myfile2文件重命名为myfile_back

E_WARNING

一些文件系统函数在失败时发出E_WARNING。 这是运行时警告(非致命错误)。 脚本的执行不会停止。

PHP 在这方面不一致。 并非所有文件系统函数都发出此警告-大多数函数仅在失败时才返回错误值。

custom_error_handler.php

<?php

set_error_handler("mywarning_handler", E_WARNING);

r = unlink('image1.png');

if (r) {

    echo "File successfully deleted\n";
}

function mywarning_handler(errno,errstr) {

    echo "Failed to delete file\n";
    echo "errstr:errno\n";
}

?>

在脚本中,我们删除文件并提供自定义错误处理程序。

set_error_handler("mywarning_handler", E_WARNING);

使用set_error_handler()函数设置自定义错误处理程序。

function mywarning_handler(errno,errstr) {

    echo "Failed to delete file\n";
    echo "errstr:errno\n";
}

处理程序将收到错误号和错误字符串作为参数。

$ php custom_error_handler.php 
Failed to delete file
unlink(image1.png): No such file or directory: 2

当没有image1.png要删除时,custom_error_handler.php提供此输出。

目录

dirname()函数返回父目录的路径。 从 PHP 7 开始,我们可以提供一个可选的 levels 参数,该参数指示要上升的父目录的数量。

parent_directories.php

<?php

home_dir = getenv("HOME");

echo dirname(home_dir). PHP_EOL;
echo dirname("/etc/") . PHP_EOL;
echo dirname(".") . PHP_EOL;
echo dirname("/usr/local/lib", 2) . PHP_EOL;

?>

在脚本中,我们打印四个目录的父目录。

$home_dir = getenv("HOME");

我们使用getenv()函数来获取当前用户的主目录。

echo dirname($home_dir). PHP_EOL;

此行显示用户主目录的父目录。

echo dirname(".") . PHP_EOL;

在这里,我们打印当前工作目录的父目录。

echo dirname("/usr/local/lib", 2) . PHP_EOL;

在这一行中,我们打印/usr/local/lib目录的第二个父目录。

$ php parent_directories.php 
/home
/
.
/usr

这是parent_directories.php的输出。

getcwd()函数返回当前工作目录,chdir()函数将当前工作目录更改为新目录。

current_directory.php

<?php

cd = getcwd();

echo "Current directory:" .cd . PHP_EOL;

chdir("..");

cd2 = getcwd();

echo "Current directory:" .cd2 . PHP_EOL;

?>

该脚本可与getcmd()chdir()函数一起使用。

$ php current_directory.php 
Current directory:/home/janbodnar/prog/phpfiles
Current directory:/home/janbodnar/prog

这是脚本的示例输出。

列出目录

在以下五个示例中,我们列出了目录的内容。 有几种方法可以完成此任务。

list_dir1.php

<?php

folder = '/home/janbodnar/prog';fh = opendir(folder);

if (fh === false) {

    exit("Cannot open directory\n");
}

while (false !== (entry = readdir(fh))) {
    echo "entry\n";
}

closedir(fh);

?>

opendir()函数打开目录句柄。 readdir()函数从目录句柄读取条目。 在脚本末尾使用closedir()函数关闭目录的句柄。

is_dir()函数判断文件名是否为目录,is_file()函数判断文件名是否为文件。

list_dir2.php

<?php

folder = '/home/janbodnar/prog/';fh = opendir(folder);

if (fh === false) {

    exit("Cannot open directory\n");
}

dirs = [];files = [];

while (false !== (entry = readdir(fh))) {

    if (is_dir(folder . '/' .entry)) {

        array_push(dirs,entry);
    }

    if (is_file(folder . '/' .entry)) {

        array_push(files,entry);
    }
}

echo "Directories:\n";

foreach (dirs asdr) {
    echo "dr\n";   
}

echo "Files:\n";

foreach (files as myfile) {
    echo "myfile\n";   
}

closedir($fh);

?>

在第二个示例中,我们将条目分为子目录和文件。 该脚本首先打印子目录,然后打印所检查目录的文件。

if (is_dir(folder . '/' .entry)) {

    array_push(dirs,entry);
}

必须提供is_dir()函数的目录的完整路径。

glob()函数查找与模式匹配的路径名。

list_dir3.php

<?php

foreach (glob('/home/janbodnar/*', GLOB_ONLYDIR) as dir) {

    echo "dir\n";
}

?>

使用GLOB_ONLYDIR标志,glob()函数仅返回与模式匹配的目录条目。

scandir()是高级函数,用于列出指定路径内的文件和目录。 该函数从目录返回文件和目录的数组。

list_dir4.php

<?php

files = scandir('.', SCANDIR_SORT_DESCENDING);

print_r(files);

?>

该脚本打印当前工作目录的文件和子目录的数组。 SCANDIR_SORT_DESCENDING标志以字母降序对条目进行排序。

在前面的示例中,我们仅列出了一个目录的内容; 我们没有包括子目录的元素。 使用RecursiveDirectoryIteratorRecursiveIteratorIterator类,我们可以轻松地使用递归遍历文件系统目录。 换句话说,我们遍历所有子目录,直到列出目录树中的所有项目。

list_dir5.php

<?php

folder = '/home/janbodnar/prog/';rdi = new RecursiveDirectoryIterator(folder);rii = new RecursiveIteratorIterator(rdi);

foreach (rii as filename) {

    echo "filename\n";
}

?>

该脚本将打印所有深度级别的给定目录的所有项目。

路径

路径是计算机文件的完整指定名称,包括文件在文件系统目录结构中的位置。 realpath()函数返回规范的绝对路径名,basename()函数返回路径的尾随名称部分。

paths.php

<?php

echo realpath("myfile.txt") . PHP_EOL;

echo basename("/home/janbodnar/prog/phpfiles/myfile.txt") . PHP_EOL;
echo basename("/home/janbodnar/prog/phpfiles/myfile.txt", ".txt") . PHP_EOL;

?>

该脚本使用realpath()basename()函数。

echo basename("/home/janbodnar/prog/phpfiles/myfile.txt", ".txt") . PHP_EOL;

如果我们指定第二个参数,即后缀名,则它也会从路径名中删除。

$ php paths.php 
/home/janbodnar/prog/phpfiles/myfile.txt
myfile.txt
myfile

这是paths.php示例的输出。

pathinfo()函数返回有关文件路径的信息。

path_info.php

<?php

path_parts = pathinfo('myfile.txt');

echopath_parts['dirname'] . PHP_EOL;
echo path_parts['basename'] . PHP_EOL;
echopath_parts['extension'] . PHP_EOL;
echo $path_parts['filename'] . PHP_EOL;

?>

该函数返回一个包含以下元素的关联数组:dirname,basename,扩展名(如果有)和文件名。

$ php path_info.php 
.
myfile.txt
txt
myfile

这是输出。

创建文件

fopen()函数打开文件或 URL。 函数的第一个参数是文件名,第二个是打开窗口的模式。 例如,'r'模式打开仅用于读取,'w'模式仅用于写入。 如果我们以'w'模式打开文件,但该文件不存在,则会创建该文件。

fopen()返回文件的句柄。 这是一个用于操作文件的对象。 例如,我们将其传递给fwrite()函数以写入文件。

create_file.php

<?php

filename = "names.txt";

if (file_exists(filename)) {

    exit("The file already exists\n");
}

fh = fopen(filename, 'w');

if (fh === false) {

    exit("Cannot create file\n");
}

echo "Successfully created file\n";

fclose(fh);

?>

该示例创建一个名为names.txt的新文件。

if (file_exists($filename)) {

    exit("The file already exists\n");
}

首先,我们检查文件是否存在。

$fh = fopen('names.txt', 'w');

创建names.txt文件,并返回该文件的句柄。

fclose($fh);

我们使用fclose()函数关闭文件句柄。

读取文件

在下一个示例中,我们将读取文件内容。

fread()从句柄引用的文件指针中读取最多length个字节。 读取length字节或到达 EOF(文件末尾)后,读取停止。

read_file.php

<?php

fh = fopen('balzac.txt', 'r');

if (fh === false) {

    exit("Cannot open file for reading\n");
}

while (!feof(fh)) {chunk = fread(fh, 1024);

    if (chunk === false) {

        exit("Cannot read from file\n");
    }

    echo chunk;    
}    

fclose(fh);

?>

该示例使用fread()函数读取整个文件,并将其输出到控制台。

while (!feof(fh)) {chunk = fread(fh, 1024);

    if (chunk === false) {

        exit("Cannot read from file\n");
    }

    echo $chunk;    
}    

feof()测试文件指针上的文件结尾。 fread()每 1 KB 的块读取文件,直到达到 EOF。

$ php read_file.php balzac.txt
Honoré de Balzac, (born Honoré Balzac, 20 May 1799 – 18 August 1850)
was a French novelist and playwright. His magnum opus was a sequence 
of short stories and novels collectively entitled La Comédie Humaine, 
which presents a panorama of French life in the years after the 1815 
Fall of Napoleon Bonaparte.

这是read_file.php示例的输出。

在第二个示例中,我们利用fgets()函数从文件句柄读取一行。

read_file2.php

<?php

fh = fopen('balzac.txt', 'r');

if (fh === false) {

    exit("Cannot open file for reading\n");
}

while (!feof(fh)) {line = fgets(fh);

    if (line === false) {

        exit("Cannot read from file\n");
    }    

    echo line;
}    

fclose(fh);

?>

该示例逐行读取balzac.txt文件的内容。

file()是将整个文件读入数组的高级函数。

read_file3.php

<?php

lines = file('balzac.txt');

if (lines === false) {

    exit("Cannot read file\n");
}

foreach (lines asline) {

    echo $line;
}

?>

在此示例中,我们使用file()函数一次读取了整个文件。 我们使用foreach循环遍历返回的数组。

file_get_contents()是另一个高级函数,它将整个文件读取为字符串。

read_file4.php

<?php

content = file_get_contents('balzac.txt');

if (content === false) {

    exit("Cannot read file\n");
}

echo "$content";

?>

该示例使用file_get_contents()函数一次读取了整个文件。 它以字符串形式返回数据。

读取格式化的数据

fscanf()函数根据格式分析文件的输入。 每次对fscanf()的调用都会从文件中读取一行。

$ cat items.txt 
coins 5
pens 6
chairs 12
books 20

我们将解析items.txt文件。

read_formatted_data.php

<?php

fh = fopen("items.txt", "r");

if (fh === false) {

    exit("Cannot read file\n");
}

while (data = fscanf(fh, "%s %d")) {

    list(item,quantity) = data;       echo "item: quantity\n";
}

fclose(fh);

?>

fscanf()函数使用格式说明符来读取字符串和数字。

读取网页

PHP 文件系统函数还可用于读取网页。

read_page.php

<?php

ph = fopen("http://www.something.com", "r");

if (ph === false) {

    exit("Failed to open stream to URL\n");
}

while (!feof(ph)) {buf = fread(ph, 1024);

    if (buf === false) {

        exit("Cannot read page\n");
    }

    echo buf;    
}

fclose(ph);

?>

我们从一个名为www.something.com的小型网站上阅读了一个页面。

$ph = fopen("http://www.something.com", "r");

使用fopen()函数,我们打开网页的句柄。

while (!feof(ph)) {buf = fread(ph, 1024);

    if (buf === false) {

        exit("Cannot read page\n");
    }

    echo $buf;   
}

我们阅读网页直至结束。 feof()用于测试网页的结尾。 使用fread()函数以 1 KB 的块读取页面。

$ php read_page.php 
<html><head><title>Something.</title></head>
<body>Something.</body>
</html>

这是read_page.php脚本的输出。

以下示例使用高级函数来读取同一网页。

read_page2.php

<?php

page = file_get_contents('http://www.something.com');

if (page === false) {

    exit("Cannot read page\n");
}

echo $page;

?>

file_get_contents()一次读取整个网页。

fgetss()函数从文件句柄读取一行并剥离 HTML 标签。

read_page3.php

<?php

ph = fopen("http://www.something.com", "r");

if (ph === false) {

    exit("Failed to open stream to URL\n");
}

while (!feof(ph)) {buf = fgetss(ph, 1024);

    if (buf === false) {

        exit("Cannot read from page\n");
    }

    echo buf;
}

fclose(ph);

?>

我们阅读www.something.com网页的内容并剥离其 HTML 标签。

$ php read_page3.php 
Something.
Something.

这是示例的输出; 输出包含页面正文中的标题和文本。

写入文件

fwrite()函数将字符串写入文件句柄引用的文件。

write_file.php

<?php

fh = fopen('names.txt', 'w');

if (fh === false) {

    exit("Cannot open file\n");
}

r = fwrite(fh, 'Jane' . PHP_EOL);    
check_retval(r);r = fwrite(fh, 'Lucy' . PHP_EOL);
check_retval(r);

r = fwrite(fh, 'Mark' . PHP_EOL);
check_retval(r);r = fwrite(fh, 'Lubos' . PHP_EOL);
check_retval(r);

fclose(fh);

function check_retval(val) {

    if ($val === false) {

        exit("Cannot write to file\n");
    }
}

?>

我们在写入模式下打开names.txt并向其中写入四行。

$fh = fopen('names.txt', 'w');

fopen()函数以写入模式打开文件。 如果文件不存在,则会自动创建。

$r = fwrite($fh, 'Jane' . PHP_EOL); 

使用fwrite()函数,我们在文件中写入一行。 该函数将文件句柄作为其第一个参数。

$ php write_file.php 
$ cat names.txt 
Jane
Lucy
Mark
Lubos

我们写入names.txt文件并检查其内容。

我们可以使用高级file_put_contents()方法将字符串一次性写入文件。

write_file2.php

<?php

filename = "names.txt";buf = file_get_contents(filename);

if (buf === false) {

    exit("Cannot get file contents\n");
}

buf .= "John\nPaul\nRobert\n";r = file_put_contents(filename,buf);

if ($r === false) {

    exit("Cannot write to file\n");
}

?>

在示例中,我们使用file_get_contents()函数读取names.txt文件的内容,并使用file_put_contents()函数附加新字符串。

可读,可写,可执行文件

is_readable()is_writable()is_executable()函数检查文件是否可读,可写和可执行。

rwe.php

<?php

filename = "myfile.txt";

echo get_current_user() . PHP_EOL;          

if (is_readable(filename)) {

    echo "The file can be read\n";
} else {

    echo "Cannot read file\n";
}

if (is_writable(filename)) {

    echo "The file can be written to\n";
} else {

    echo "Cannot write to file\n";
}

if (is_executable(filename)) {

    echo "The file can be executed\n";
} else {

    echo "Cannot execute file\n";
}

?>

我们在myfile.txt文件上运行三个函数。 该脚本检查当前用户的这些属性。

$ php rwe.php 
janbodnar
The file can be read
The file can be written to
Cannot execute file

janbodnar用户可以读写该文件,但不能执行。

文件时间

Linux 上有三种文件时间:上次访问时间,上次更改时间和上次修改时间。 以下 PHP 函数确定这些时间:fileatime()filectime()filemtime()

file_times..php

<?php

filename = "myfile.txt";atime =  fileatime(filename);ctime =  filectime(filename);mtime =  filemtime(filename);

echo date("F d, Y H:i:s\n",atime);
echo date("F d, Y H:i:s\n", ctime);
echo date("F d, Y H:i:s\n",mtime);

?>

该脚本打印myfile.txt文件的文件时间。

$ php file_times.php 
April 20, 2016 17:52:54
April 20, 2016 17:53:33
April 20, 2016 17:52:29

这是file_times.php脚本的示例输出。

文件权限

文件系统对不同的用户和用户组强制执行文件权限。 fileperms()函数获得文件许可; 它以数字方式返回文件的权限。

file_permissions.php

<?php

perms = fileperms("myfile.txt");

echo decoct(perms & 0777) . PHP_EOL;

info .= ((perms & 0x0100) ? 'r' : '-');
info .= ((perms & 0x0080) ? 'w' : '-');
info .= ((perms & 0x0040) ?
            ((perms&0x0800) ? 's' : 'x' ) :
            ((perms & 0x0800) ? 'S' : '-'));

info .= ((perms & 0x0020) ? 'r' : '-');
info .= ((perms & 0x0010) ? 'w' : '-');
info .= ((perms & 0x0008) ?
            ((perms&0x0400) ? 's' : 'x' ) :
            ((perms & 0x0400) ? 'S' : '-'));

info .= ((perms & 0x0004) ? 'r' : '-');
info .= ((perms & 0x0002) ? 'w' : '-');
info .= ((perms & 0x0001) ?
            ((perms&0x0200) ? 't' : 'x' ) :
            ((perms & 0x0200) ? 'T' : '-'));            

echo "$info\n";  

?>

该脚本确定myfile.txt的文件许可权。 权限以 Unix 样式打印到控制台。

echo decoct($perms & 0777) . PHP_EOL;

Unix 上的权限传统上以八进制表示形式编写。 decoct()函数将十进制表示形式转换为八进制形式。

$info .= (($perms & 0x0100) ? 'r' : '-');

在这一行中,我们检查文件权限是否允许文件所有者读取它。

$ php file_permissions.php 
660
rw-rw----

这是file_permissions.php脚本的示例输出。

可以使用chmod()函数更改文件权限。

.php

<?php

perms1 = fileperms("myfile.txt");

echo decoct(perms1 & 0777) . PHP_EOL;

r = chmod("myfile", 0660);

if (r) {

    echo "File mode successfully changed\n";
} else {

    exit("Failed to change file mode\n");
}

perms2 = fileperms("myfile");

echo decoct(perms2 & 0777) . PHP_EOL;

?>

该脚本更改myfile.txt文件的权限。

$r = chmod("myfile", 0660);

chmod函数在其第二个参数中接受权限作为八进制值。 八进制值以 0 开头。

$ php file_permissions2.php 
664
File mode successfully changed
660

文件的权限从 664 更改为 660。

CSV 文件格式

fgetcsv()函数从 CSV(逗号分隔值)文件中读取一行; 它返回一个包含读取字段的索引数组。 fputcsv()函数将一行格式设置为 CSV 并将其写入文件。

csv_output.php

<?php

nums = [1, 2, 5, 3, 2, 6, 4, 2, 4,    8, 7, 3, 8, 5, 4, 3];fh = fopen('numbers.csv', 'w');

if (fh === false) {

    exit("Failed to open file\n");
}r = fputcsv(fh,nums);

if (r === false) {

    exit("Failed to write values\n");
} 

echo "The values have been successfully written\n";

fclose(fh);

?>

该脚本将数组中的数字写入 CSV 文件。

$ php csv_output.php 
The values have been successfully written
$ cat numbers.csv 
1,2,5,3,2,6,4,2,4,8,7,3,8,5,4,3

我们运行脚本并检查文件内容。

在以下示例中,我们从 CSV 文件读取数据。

csv_input.php

<?php

fh = fopen('numbers.csv', 'r');

if (fh === false) {

    exit("Failed to open file\n");
}

while ((data = fgetcsv(fh)) !== false) {

    num = count(data);

    for (i=0;i < num;i++) {

        echo "data[i] ";
    }
}

echo "\n";

fclose($fh);

?>

该脚本使用fgetcsv()numbers.csv文件中读取值,并将其打印到控制台中。

$ php csv_input.php 
1 2 5 3 2 6 4 2 4 8 7 3 8 5 4 3 

这是csv_input.php脚本的输出。

磁盘空间

disk_total_space()函数以字节为单位返回文件系统或磁盘分区的总大小,disk_total_space()函数以字节为单位返回文件系统或磁盘分区上的可用空间。

disk_space.php

<?php

const BYTES_IN_GIGABYTE = 1073741824;

total_space_bytes = disk_total_space("/");

if (total_space_bytes === false) {

    exit("The disk_total_space() failed\n");
}

free_space_bytes = disk_free_space("/");

if (free_space_bytes === false) {

    exit("The disk_free_space() failed\n");
}

total_space_gb = floor(total_space_bytes / BYTES_IN_GIGABYTE);
free_space_gb = floor(free_space_bytes / BYTES_IN_GIGABYTE);

echo "Total space: total_space_gb GB\n";
echo "Free space:free_space_gb GB\n";

?>

该脚本计算根分区上的总空间和可用空间。 该空间被转换为千兆字节。

$ php disk_space.php 
Total space: 289 GB
Free space: 50 GB

您可能也对以下相关教程感兴趣: PHP PDO 教程PHP 教程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程