Articles Catalogue
- Resources
- brief introduction
- fread, fwrite Basic Knowledge
- 3.1 Nutx configuration options
- 3.2 Definition of Nutx File Handles and File Descriptors
- 3.2.1 file_struct file structure
- 3.2.2 file_opcreation framework
- 3.2.3 Standard Input, Standard Output, Standard Error
- Standard interface definition for 3.2.4 posix
- 3.3 Implementation of fopen interface
- Implementation of 3.4 fwrite interface
- 3.5 File System Principles
- 3.6 sd card file write operation process of this sd card file
- summary
Resources
nuttx_fread_fwrite.md
brief introduction
The Realization Principle of fwrite, write and printf
#include <stdio.h> #include <unistd.h> #include <string.h> #include <errno.h> int main(int argc,char**argv){ char buf[]="hello,world\n"; //Print with'printf' printf("%s",buf); //Print with'fwrite' fwrite(buf,strlen(buf), 1,stdout); //use 'write' function to print char write(STDOUT_FILENO,&buf,strlen(buf)); return(0); }
results of enforcement
hello,world hello,world hello,world
fread, fwrite Basic Knowledge
The operation of files under UNIX is fopen, fread, fwrite, and open, read, write. The difference between them is that fopen series is the standard C library function; open series is defined by POSIX, is the system call file handles in UNIX system, also known as file structure pointer, file descriptor. Descriptors is an integer variable. As we often know, stdout (standard output), stdin (standard input), stderr (standard error), are all file handles. Each file handle corresponds to a file descriptor, stdout, stdin, stderr, which corresponds to the file description of 0, 1, 2 FREAD and fwrite interfaces NAME fread. Fwrite - binary stream input / output
SYNOPSIS
#include <stdio.h> size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
3.1 Nutx configuration options
# CONFIG_STDIO_DISABLE_BUFFERING is not set CONFIG_STDIO_BUFFER_SIZE=32 #Configuration file buffer size CONFIG_STDIO_LINEBUFFER=y #Whether to Open File Buffer
3.2 Definition of Nutx File Handles and File Descriptors
3.2.1 file_struct file structure
File structure file location NuttX/nuttx/include/nuttx/fs/fs.h, file structure, including the description file buffer, this is a great feature of the file structure.
#if CONFIG_NFILE_STREAMS > 0 struct file_struct { int fs_fd; //Binding file descriptors #ifndef CONFIG_STDIO_DISABLE_BUFFERING sem_t fs_sem; /* For thread safety */ pid_t fs_holder; /* Holder of sem */ int fs_counts; /* Number of times sem is held */ FAR unsigned char *fs_bufstart; //The head of the execution buffer, which is dynamically allocated by f_open FAR unsigned char *fs_bufend; /* Pointer to 1 past end of buffer */ FAR unsigned char *fs_bufpos; /* Current position in buffer */ FAR unsigned char *fs_bufread; /* Pointer to 1 past last buffered read char. */ #endif uint16_t fs_oflags; /* Open mode flags */ uint8_t fs_flags; /* Stream flags */ #if CONFIG_NUNGET_CHARS > 0 uint8_t fs_nungotten; /* The number of characters buffered for ungetc */ unsigned char fs_ungotten[CONFIG_NUNGET_CHARS]; #endif };
3.2.2 file_opcreation framework
Definition of file descriptor Each file descriptor of linux binds a static file creation file interface, binds f_priv-driven objects, and operates on the underlying registers.
struct file { int f_oflags; /* Open mode flags */ off_t f_pos; /* File position */ FAR struct inode *f_inode; /* Driver or file system interface */ void *f_priv; /* Per file driver private data */ }; /* This defines a list of files indexed by the file descriptor */ #if CONFIG_NFILE_DESCRIPTORS > 0 struct filelist { sem_t fl_sem; /* Manage access to the file list */ struct file fl_files[CONFIG_NFILE_DESCRIPTORS]; };
3.2.3 Standard Input, Standard Output, Standard Error
The stream of standard input and output is a file handle created automatically by each thread when it is created and bound automatically to file descriptors 0, 1, 2.
#define stdin (&sched_getstreams()->sl_streams[0]) #define stdout (&sched_getstreams()->sl_streams[1]) #define stderr (&sched_getstreams()->sl_streams[2])
Standard interface definition for 3.2.4 posix
struct file_operations { /* The device driver open method differs from the mountpoint open method */ int (*open)(FAR struct file *filep); /* The following methods must be identical in signature and position because * the struct file_operations and struct mountp_operations are treated like * unions. */ int (*close)(FAR struct file *filep); ssize_t (*read)(FAR struct file *filep, FAR char *buffer, size_t buflen); ssize_t (*write)(FAR struct file *filep, FAR const char *buffer, size_t buflen); off_t (*seek)(FAR struct file *filep, off_t offset, int whence); int (*ioctl)(FAR struct file *filep, int cmd, unsigned long arg); /* The two structures need not be common after this point */ #ifndef CONFIG_DISABLE_POLL int (*poll)(FAR struct file *filep, struct pollfd *fds, bool setup); #endif #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS int (*unlink)(FAR struct inode *inode); #endif
3.3 Implementation of fopen interface
FAR FILE *fopen(FAR const char *path, FAR const char *mode) //open file descriptors fd = open(path, oflags, 0666); //Bind file handle to os -> ret = fs_fdopen(fd, oflags, NULL); //Dynamic file buffer to locate start and end. stream->fs_bufstart = group_malloc(tcb->group, CONFIG_STDIO_BUFFER_SIZE); stream->fs_bufend = &stream->fs_bufstart[CONFIG_STDIO_BUFFER_SIZE]; stream->fs_bufpos = stream->fs_bufstart; stream->fs_bufread = stream->fs_bufstart; //Binding files are described in the os stream stream->fs_fd = fd; };
Implementation of 3.4 fwrite interface
size_t fwrite(FAR const void *ptr, size_t size, size_t n_items, FAR FILE *stream) -> size_t full_size = n_items * (size_t)size; -> bytes_written = lib_fwrite(ptr, full_size, stream); //Write all bytes //Write the data to the file buffer first for (dest = stream->fs_bufpos; gulp_size > 0; gulp_size--) *dest++ = *src++; //Buffers are full before they are written to the real device if (dest >= stream->fs_bufend) int bytes_buffered = lib_fflush(stream, false); -> bytes_written = write(stream->fs_fd, src, nbuffer);3.3.3 fread Implementation process size_t fread(FAR void *ptr, size_t size, size_t n_items, FAR FILE *stream) bytes_read = lib_fread(ptr, full_size, stream); //If the buffer has data, get the data directly from the buffer first. while ((count > 0) && (stream->fs_bufpos < stream->fs_bufread)) *dest++ = *stream->fs_bufpos++; count--; } buffer_available = stream->fs_bufend - stream->fs_bufread; //If the data is insufficient, read directly from the file -> if (count > buffer_available) bytes_read = read(stream->fs_fd, dest, count); //If the required data is smaller than the buffer size, read the entire buffer size -> if (count < buffer_available) bytes_read = read(stream->fs_fd, dest, buffer_available);3.4 printf Interface Implementation printf The lowest level function isup_putc() This function is smt32 Blocking waits for the sending to complete, and this up_putc It can be invoked anywhere.int printf(FAR const IPTR char *fmt, ...) int vfprintf(FAR FILE *stream, FAR const IPTR char *fmt, va_list ap) ->lib_stdoutstream(&stdoutstream, stream); -> outstream->public.put = stdoutstream_putc; -> result = fputc(ch, sthis->stream); -> ret = lib_fwrite(&buf, 1, stream); // Here's the same implementation as fwrite -> if (dev->isconsole) -> ret = uart_irqwrite(dev, buffer, buflen); ->uart_putc('\r'); // #define uart_putc(ch) up_putc(ch) -> void up_lowputc(char ch) -> while ((getreg32(CONSOLE_BASE+A1X_UART_LSR_OFFSET) & UART_LSR_THRE) == 0); putreg32((uint32_t)ch, CONSOLE_BASE+A1X_UART_THR_OFFSET); -> n = lib_vsprintf(&stdoutstream.public, fmt, ap); -> obj->put(obj, FMT_CHAR); if (FMT_CHAR == '\n') (void)obj->flush(obj);
3.5 File System Principles
File system mounting filesystem is a problem I have been puzzled about, which finally understands the problem of file system mounting. The difference between block device and character device is that the character device drives the registered device node, while open and write can operate character device directly, while the registration of block device is not given to wr directly. The file system is registered at the mount point to operate the file. Block devices, unlike character device drivers, can be processed in a single byte. flash features sector processing. Generally, SD card sectors are 512 bytes.
union inode_ops_u { FAR const struct file_operations *i_ops; /* Driver operations for inode *// FAR const struct mountpt_operations *i_mops; /* Operations on a mountpoint */ }; //Mount file system if mount -t vfat /dev/mmcsd0 /fs/microsd //mount.c mountpt_inode->u.i_mops = mops; //File system and device node mounted well
3.6 sd card file write operation process of this sd card file
The write of posix calls the file system fat_write, and then the drive mmcsd_writessize_t write (int fd, FAR const void*buf, size_t nbytes)
//write of fat file system interface ret = fat_hwwrite(fs, userbuffer, ff->ff_currentsector, nsectors); //Driver interface for calling mmcsd card -> ssize_t nSectorsWritten = inode->u.i_bops->write(inode, buffer, sector, nsectors); ->mmcsd_write,/* mmcsd write*/
summary
userbuffer, ff->ff_currentsector, nsectors);
// driver interface for calling mmcsd card
-> ssize_t nSectorsWritten =
inode->u.i_bops->write(inode, buffer, sector, nsectors);
-> mmcsd_write, /* mmcsd write*/
# Summary Through the above analysis, our FREAD and fwrite, and printf are buffered. The condition that the contents written by fwrite are refreshed to the SD card is that the buffer is full before it can be written to the physical sd. Fread reads the data of the buffer from the physical sector every time. For example, the buffer is 32 bytes, FREAD takes 10 bytes, and FREAD reads 3 bytes directly. 2 bytes, buffered to the file buffer, the remaining 22 bytes, the next time the user calls fread, read 10 bytes, 10 bytes less than the remaining 22 bytes of the buffer, you can read directly from the buffer, which can improve the size of the buffer. Printf has byte-independent characteristics, because printf processes all characters, then the efficient method is to determine whether to receive the return symbol, you can refresh the buffer, and fgetc is to wait for the received data to have the return symbol, before processing. Block device [fwrite [c library] - > write [system call] - > fat_write [file system] - > mmcsd_write [SD driver] [character device [fwrite [c library] - > write [system call] - > serial_write [serial driver]