对大小是2500字节的文件进行copy操作,
如果缓冲区大小是100字节,需要25次read()和write();
如果缓冲区大小是1000字节,需要3次read() 和write()
缓冲区之所以对文件I/O性能有着显著的影响,这是因为每一次的read()、write()操作 必须经过系统调用,也就是内核访问。用户空间的程序每次必须经过内核才可以访问位 于 磁盘上的文件。
引入缓冲区,就是不必每次访问系统呼叫,只需一次调用,将内容放入缓冲区,每次用 户空间的程序可以访问缓冲区的内容,直至缓冲区的内容被消耗掉。
使用。磁盘是数据块集合,内核会对磁盘上的数据块作缓冲。内核将磁盘上的数据块复 制到内核缓冲区中,当一个用户空间中的进程要从磁盘上读取数据时,内核一般不直接 读磁盘,而是将内核缓冲区中的数据复制到进程的缓冲区中。
当进程所要求的数据块不在内核缓冲区中,内核会把相应的数据块加入到请求数据列表中,然后把该进程挂起,接着为其他进程服务。
一段时间后,内核把相应的数据块从磁盘读到内核缓冲区,然后再把数据复制到进程的缓冲区中,最后唤醒被挂起的进程。
大约不久前,我突然接触open的时候,也在想之前是不是接触过一个fopen函数,这两 个函数有什么区别,或者为什么有两个形式?看了上面的铺垫,想必你也有想法了,对 ,或者说,这是很重要的一方面。
open系列函数与fopen系列的区别可以简单概括为:
open系列函数 fopen系列函数 一般用于打开设备文件(少数情况) 一般用于打开普通文件(大多数情况) 利用文件描述符操纵文件(int) 利用文件指针操作文件 open返回一个文件描述符 fopen返回一个文件指针 POSIX系统调用 ANSI C库函数 低层次IO 高层次IO,对open的扩展和封装 只能在POSIX操作系统上 可移植到任何操作系统 非缓冲IO 缓冲IO 只能读取二进制或普通文 可以读取一个结构 可以指定要创建文件的访 限 不能指定要创建文件的访问权限
注: 文件指针的类型为 F *fp;
总结一下,就是带f前缀的是库函数,操作对象是file stream,不带f的原生态的 操作是unix下的系统调用。
用C标准I/O库函数要时刻注意I/O缓冲区和实际文件有可能不一致,在必要时需调用fflush(3)。
又因为c标准库函数是C标准的一部分,而Unbuffered I/O函数是UNIX标准的一部分,前者放在
其实还有一个函数也是比较重要的,尤其是确保内核内的数据写入磁盘,这个函数就是
#include<unistd.h>
void sync(void)
还有一个函数也是非常重要的
#include <unistd.h>
int fsync(int fd);
int fdatasync(int fd);
/**
bool isPerfectSquare(int num){
long long L = 1, R = (num >> 1) + 1;
while(L <= R){
long long middle = L + ((R - L)>>1);
long long value = middle * middle;
if(value == num)
return true;
else if(value > num)
R = middle - 1;
else
L = middle + 1;
}
return false;
}
各方面来说,目前的编程状态属于一种特别混乱。不过,自己还好涉猎面比较广泛, 竞赛算法类的编程,还可以拿的起来;linux系统级别的,需要自己钻时间挖掘知识点
这个系列肯定不完整,以后再加上其他语言版本的。
虽然已经这么的菜了,我就先不要发表自己的负面情绪了。
和前几年的状态一样,编程的思路还是不怎么正确,或者说c/c++的基础还是太low,不 过,现在到时有一点能稳定住。
其实这样也好,那边有linux kernel的大头维持着,这边你可以继续着算法方面的研修
这一次一定要坚持下去,不然真的要和计算机说再见了。
这道题目真的很简单,我也可以写到测试几个简单的数据,结果数据一大就错误了。
还有没有搞明白题目的含义,比如,测试数据
1001
我认为是有多少个26,就是多少个A,结果人家的答案是”ALM”,我的思路完全是错误的。
先把我的错误代码放上来,好好看看自己的弱点
char str[100];
char *convertToTitle(int n){
int len = n/26 + 1;
int i;
for (i = 0; i < len - 1 ;i++){
str[i] = 'A';
}
int last_num = n - n/26*26 -1;
str[i] = (char)(last_num + 'A');
str[len] = '\0';
return str;
}
关于对单个文件的操作,应该关注这篇文章
首先在联机帮助中寻找关键字direct来查找。
man -k direct grep read
这样就被指引到了readdir这个函数中,在这里面的说明文档,有以下内容
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
这个函数返回DIR *dir记录中的下一条目录项。
在linux上,dirent结构体的内容如下:
struct dirent {
ino_t d_ino; /* inode number */
off_t d_off; /* offset to the next dirent */
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file; not supported
by all file system types */
char d_name[256]; /* filename */
};
其中的d_type的选项为:
DT_BLK This is a block device.
DT_CHR This is a character device.
DT_DIR This is a directory.
DT_FIFO This is a named pipe (FIFO).
DT_LNK This is a symbolic link.
DT_REG This is a regular file.
DT_SOCK This is a Unix domain socket.
DT_UNKNOWN The file type is unknown.
那么,与文件的操作相比较,还得有opendir,closedir等操作。
那么,ls的算法如下:
main()
opendir
while(readdir)
print d_name
closedir
那么,先看看v1.0是怎么实现的。
/*
* ls.c: implement of ls command
*/
#include<stdio.h>
#include<sys/types.h>
#include<dirent.h>
void do_ls(char *);
int main(int argc, char *argv[])
{
if( argc == 1)
do_ls(".");
else
while(--argc){
printf("%s:\n",*++argv);
do_ls(*argv);
}
}
void do_ls(char *dirname )
{
/*
* list files in directory called dirname
*/
DIR *dir_ptr; /* the directory */
struct dirent *direntp; /* each entry */
if ((dir_ptr = opendir(dirname)) == NULL)
fprintf(stderr, "ls1;cannot open %s\n",dirname);
else
{
while((direntp = readdir(dir_ptr)) != NULL)
printf("%s\n",direntp->d_name);
closedir(dir_ptr);
}
}
结果只是把所有的文件展示出来,但是还有很多的信息没有展示,比如:ls -l命令, 输出结果的排序等等。
想实现ls -l
的效果, 需要读取文件的信息状态,那么,这个信息由stst结构体提
供,相关的代码还是得看上面连接的部分
st_mode是一个16位的二进制数,图.
为了提取有效的数字,我们使用掩码技术。什么是掩码呢?就是好像带上面具将其他没 有的数据隐藏起来。
(1)掩码(masking) 会将不需要的字段置为0,需要的字段不发生变化。
(2)我们还知道整数在计算机中的表示也是二进制。这样一个普通的整数也就有了意义。
(3)与0做位与(&)操作可以将相应的bit为置为0,
(4) 使用8进制
介绍完了掩码,还必须介绍子域编码。
在 <bits/stat.h>中,有以下定义:
#define __S_IFMT 0170000 /* These bits determine file type. */
/* File types. */
#define __S_IFDIR 0040000 /* Directory. */
#define __S_IFCHR 0020000 /* Character device. */
#define __S_IFBLK 0060000 /* Block device. */
#define __S_IFREG 0100000 /* Regular file. */
#define __S_IFIFO 0010000 /* FIFO. */
if ((info.st_mode & 0170000) == 0040000)
printf("This is a directory");
然而在<sys/stat.h>中,又定义了上面的宏,有__X_IFXXX前面的__去掉了。
#include <bits/stat.h>
#if defined __USE_MISC || defined __USE_XOPEN
# define S_IFMT __S_IFMT
# define S_IFDIR __S_IFDIR
# define S_IFCHR __S_IFCHR
# define S_IFBLK __S_IFBLK
# define S_IFREG __S_IFREG
# ifdef __S_IFIFO
# define S_IFIFO __S_IFIFO
# endif
# ifdef __S_IFLNK
# define S_IFLNK __S_IFLNK
# endif
# if (defined __USE_MISC || defined __USE_UNIX98) \
&& defined __S_IFSOCK
# define S_IFSOCK __S_IFSOCK
# endif
#endif
更简单的方法是使用<sys/stat.h>中的macro,注意,这里版本的不同文件所处的位置也 不同的. 下面,具体的宏实现如下:
/* Test macros for file types. */
#define __S_ISTYPE(mode, mask) (((mode) & __S_IFMT) == (mask))
#define S_ISDIR(mode) __S_ISTYPE((mode), __S_IFDIR)
#define S_ISCHR(mode) __S_ISTYPE((mode), __S_IFCHR)
#define S_ISBLK(mode) __S_ISTYPE((mode), __S_IFBLK)
#define S_ISREG(mode) __S_ISTYPE((mode), __S_IFREG)
#ifdef __S_IFIFO
# define S_ISFIFO(mode) __S_ISTYPE((mode), __S_IFIFO)
#endif
#ifdef __S_IFLNK
# define S_ISLNK(mode) __S_ISTYPE((mode), __S_IFLNK)
#endif
#if defined __USE_MISC && !defined __S_IFLNK
# define S_ISLNK(mode) 0
#endif
这里,还可以定义如下宏:
#define S_ISFIFO(m) (((m)&(0170000)) == 0010000)
先提供struct passwd 的源码:
/* defined in pwd/pwd.h */
/* The passwd structure. */
struct passwd
{
char *pw_name; /* Username. */
char *pw_passwd; /* Password. */
__uid_t pw_uid; /* User ID. */
__gid_t pw_gid; /* Group ID. */
char *pw_gecos; /* Real name. */
char *pw_dir; /* Home directory. */
char *pw_shell; /* Shell program. */
};
补全命令:
大多数unix默认的shell是 ksh, ksh要用连续两次 ESC 来补全命令,HPUX默认的Shell是Posix shell
上条命令、下条命令: 同 vi 操作一模一样,先按 ESC键 进入命令模式
k 上一条 j 下一条 h 左移 l 右移 x 删除
开启AIX KSH 自动补全功能 AIX系统下默认的Shell是ksh,不同于Linux下的bash,ksh不直接支持dos-key的便捷操作,如果没有找到途径,每条命令都要重新敲入,实在是很麻烦。Ksh还不支持文件名自动补全,这也是另外一个遗憾。 实现方法: #set -o vi 上滚一条命令是ESC+k 下滚一条命令是ESC+j ESC + ESC -
自动补全是ESC+\
例如,想要自动补全,就先按ESC,再按\ 参考