美文网首页
C 标准库 - stdio.h

C 标准库 - stdio.h

作者: my_passion | 来源:发表于2022-07-30 17:19 被阅读0次

I/O 函数 Return value 总结, 字符处理函数 除外

(1) returnType 为 整型/size_t, return value 可能不用于表示个数, 此时一般以 0 表示 success, nonZero 表示 fail

Return 
    0      , success
    nonZero, else

(2) returnType 为 int/size_t, return value 可能用于表示 个数, 此时一般表示 successful 处理的个数

    fread 
    fwrite

1 类型

1.1 file position indicator: fpos_t // 类型

可用于 store (被 fgetpos) 和 restore (被 fsetpos) 文件 position

1.2 size_t

无符号整型

    sizeof 结果类型

1.3 FILE: 存 file stream

2 Predefined standard streams

    stdin 

    stdout

    stderr 

3 File 访问

fopen   // opens a file
fclose  // closes a file

fflush  // synchronizes an output stream with the actual file

setvbuf // sets the buffer, and its size for a file stream
setbuf  // sets the buffer for a file stream

(1) FILE* fopen(const char* filename, const char* mode);

Return
    ptr to file stream, success
    
    NULL              , else    
        POSIX requires that `errno be set` in this case

(2) int fclose(FILE* stream );

I/O buf data 丢掉 / write from/to stream

(3) int fflush(FILE* stream);

[1] fflush(stdout/outputDevice);
    writes unwritten data (from stream's buffer) to associated output device.

[2] fflush(stdin); 
    the behavior is undefined.
    非 C标准, `gcc 不支持`

Note: If stream is a null pointer, all open output streams are flushed

(4) int setvbuf(FILE* stream, char* buffer, int bufMode, size_t bufSize );

    bufMode: _IOFBF / _IOLBF / _IONBF   

(5) void setbuf(FILE* stream, char* buffer);

Sets internal buffer for stream. 至少 BUFSIZ characters long

Note

[1] 若 BUFSIZ 并非合适的 buffer size, setvbuf 可被用来 change it

封装 setvbuf, 只留下 前2个参数

buffer == NULL/!= NULL 时, 分别等价于

    setvbuf(stream, NULL, _IONBF, 0)        // 关 buf
    setvbuf(stream, buffer, _IOFBF, BUFSIZ) // 全 buf + BUFSIZ(512 Byte)

Note

[2] 应该用于 stream 关联到 文件后, 任何其他操作前

[3] 常见错误: stdin/stdout 的 buffer 数组 lifetime 先于 程序/main 结束

问题: 程序离开 main 后, 准备 clear buf, 但 buffer lifetime 已结束

#include <stdio.h> 

int main() 
{ 
    int c; 
    char buf[BUFSIZ]; 
    setbuf(stdout,buf); 
    while( (c=getchar())!= EOF) 
        putchar(c); 
}
gcc 下 汇编可看出问题
image.png

solution: buffer array 放 main 之外

#include <stdio.h> 
char buf[BUFSIZ]; 
int main() 
{ 
    int c;  
    setbuf(stdout,buf); 
    while( (c=getchar())!= EOF) 
        putchar(c); 
}

应用

[1] 关 stdout buf, 以 立即输出

    setbuf(stdout, NULL)

    //<=>
    setvbuf(stdout, NULL, _IOFBF, 0)` 设为全缓冲

[2] 关 stdin buf, 即 清空 stdin buf

    setbuf(stdin, NULL)

    // <=>
    void clear_stdin_buf()
    {
        int ch;
        while( (ch = getchar() ) != '\n' && ch != EOF)
            ; 
    }
#include <stdio.h>
char buf[BUFSIZ];
int main()
{
    // 指定 stdout 缓冲区 为 buf 
    setbuf(stdout, buf);

    // 把 hello\n 放 stdout buf, 这行执行完, 屏幕上 不打印 hello
    puts("hello");

    // 这行执行完, 屏幕上 打印 hello
    fflush(stdout);
}

4 Direct input/output: fread/fwrite

fread
    reads from a file

fwrite
    writes to a file

file position indicator 自动前移

(1) size_t fread(void* buffer, size_t size, size_t count, FILE* stream);

好像对 每个 object, 调 size 次 fgetc, reinterpreted 为 unsigned char 数组

Return: 成功 read 的 objects 数, 可能 <= count: if error 或 end-of-file occurs

fread 不区分 end-of-file 和 error, callers 必须用 feof 和 ferror 去判断 which occurred

(2) size_t fwrite(const void* buffer, size_t size, size_t count, FILE* stream );

好像对 每个 object, 调 size 次 fputc, 将 size 个 unsigned chars(视为1个object) 写进 stream

Return: 成功 write 的 objects 数, 可能 <= count: if error occurs

#include <stdio.h>
#include <stdlib.h> // malloc 

enum { SIZE = 3 };
int main(void)
{
    double a[SIZE] = { 1.,2.,3. };

    FILE* fp = fopen("test.bin", "wb"); // must use binary mode
    fwrite(a, sizeof(*a), SIZE, fp);    // writes an array of doubles
    fclose(fp);

    // === (2) 解析 二进制文件: 知道文件所存 object 类型 
    fp = fopen("test.bin", "rb");

    fseek(fp, 0, SEEK_END);      // set stream 上 文件位置指针 = offset/Bytes + whence = 文件尾
    size_t fileSize = ftell(fp); // 求 文件位置指针 相对 文件首 偏移 Bytes = fileSize
    rewind(fp);                  // set stream 上 文件位置指针 = 文件首

    size_t objectsCount = fileSize / sizeof(double);
    double* buf = (double *)malloc(fileSize); // allocate buf memory
    size_t ret = fread(buf, sizeof(double), objectsCount, fp);

    if (ret == objectsCount)
    {
        puts("Array read successfully, contents: ");
        for (size_t i = 0; i < objectsCount; ++i)
            printf("%f ", buf[i]);
        putchar('\n');
    }
    else // error handling
    {
        if (feof(fp))         // 1) EOF
            printf("Error reading test.bin: unexpected end of file\n");
        else if (ferror(fp))  // 2) error
            perror("Error reading test.bin");

    }

    free(buf);

    fclose(fp);
}
    Array read successfully, contents:
    1.000000 2.000000 3.000000

5 文件定位

ftell
    returns the current file position indicator

fgetpos
    gets the file position indicator

fseek
    moves the file position indicator to a specific location in a file

fsetpos
    moves the file position indicator to a specific location in a file

rewind
    moves the file position indicator to the beginning in a file

set 文件位置: para 数 1 / 2 / 3 => rewind / fsetpos / fseek

set stream 文件位置指针 = 文件头 / pos 所指处 / offset + whence 处

(1) void rewind(FILE* stream)

(2) int fsetpos(FILE* stream, const fpos_t* pos)

    moves file position indicator to 文件中 特定位置

If a read or write error occurs, the error indicator (ferror) for the stream is set

(3) int fseek(FILE* stream, long int offset, int whence)

whence = SEEK_SET/SEEK_CUR/SEEK_END

get 文件位置: para 数 1 / 2 => ftell/fgetpos

get stream 文件位置 = 当前文件位置指针 相对 文件首的偏移( Bytes 数 ) / pos 所指处

(4) long int ftell(FILE* stream)

Note: 必须以 二进制 打开

(5) int fgetpos(FILE* stream, fpos_t* pos)

    gets file position indicator

刚打开文件时, pos 记录文件起始位置: fpos_t pos; fgetpos(fp, &pos);

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

int main(void)
{
    enum { SIZE = 3 };

    // (1) fwrite a file
    FILE* fp = fopen("test.bin", "wb");
    assert(fp);

    double arr[SIZE] { 1.1, 2.2, 3.3};
    int rc = fwrite(arr, sizeof(double), SIZE, fp);
    assert(rc == SIZE);
    fclose(fp);

    // (2) fread one by one 
    fp = fopen("test.bin", "rb");

    double d;
    fpos_t pos;
    fgetpos(fp, &pos);                // [1] store start pos of file
    
    rc = fread(&d, sizeof(d), 1, fp); // [2] read first double
    assert(rc == 1);
    printf("First value in the file: %.1f\n", d);
            
    if(fsetpos(fp, &pos) != 0)        // [3] set/move file position back to start of file
    {
       if (ferror(fp))
       {
          perror("fsetpos()");
          fprintf(stderr,"fsetpos() failed in file %s at line # %d\n", __FILE__,__LINE__-5);
          exit(EXIT_FAILURE);
       }
    }
    
    rc = fread(&d, sizeof(d), 1, fp); // [4] read again: the first double
    assert(rc == 1);
    printf("First value in the file again: %.1f\n", d);

    rc = fread(&d, sizeof(d), 1, fp); // [5] read next elem: the second double
    assert(rc == 1);
    printf("Second value in the file: %.1f\n", d);

    fclose(fp);

    // (3) demo error handling
    rc = fsetpos(stdin, &pos);
    if (rc) 
        perror("could not fsetpos stdin");
}
First value in the file: 1.1
First value in the file again: 1.1
Second value in the file: 2.2
could not fsetpos stdin: Bad file descriptor

6 Error handling

clearerr
    clears errors

feof
    checks for the end-of-file

ferror
    checks for a file error

perror
    `displays` a character string corresponding of the `current error to stderr`

feof / ferror 返回类型 int

return 
    NonZero, EOF Flag / Error Flag is set
    0,       false

(1) void clearerr(FILE* stream)

Resets(重置 <=> 取消) EOF indicator 和 Error flag(for given stream)

(2) int feof(FILE* stream)

Checks if EOF indicator (associated with stream) is set
<=>
Checks if `end of (the given file) stream has been reached`

(3) int ferror(FILE* stream)

Check if  Error flags is set
<=>
Checks the given stream for errors. 

(4) void perror(const char *str)

print 系统变量 errno 中存储的 `error code 的 文本描述` 到 stderr

print: str + 冒号 + 空格 + error code 的 文本描述

#include <stdio.h>
#include <stdlib.h>
// #include <assert.h>

int main(void)
{
    // === (1) 打开 不存在的文件
    FILE* pf= fopen("non_existent", "r");
    if (pf == NULL)
        perror("fopen() failed");
    else 
        fclose(pf);
  
    // === (2) 创建临时文件
    FILE* tmpf = tmpfile();

    fputs("abcde\n", tmpf);
    rewind(tmpf);

    int ch;

    // exit: tmpf 文件指针 已越过 the last character => 到达 EOF <=> EOF indicator is set 
    while ( (ch = fgetc(tmpf) ) != EOF) 
        printf("%c", ch);

    if ( feof(tmpf) ) // feof(tmpf) == true/nonZero // assert( feof(pf) ); // true, assert 顺利通过
        puts("EOF indicator is set <=> EOF reached successfully");
    else if (ferror(tmpf) ) 
        puts("I/O error when reading");

    clearerr(tmpf);  // clear eof

    if ( feof(tmpf) )
        puts("EOF indicator set");
    else
        puts("EOF indicator cleared\n");
}

Note: 文件位置指针 指向 end-of-file 时, 并 不 set FILE 结构中 EOF flag, 再执行一次 读文件操作, 才会 set EOF flag, 此时调 feof(fp) 才 return true

=>

问题: feof(fp) -> 读 -> print 出错
解决: 读 -> EOF 检测 (!= EOF 或 !feof(fp) )-> print

solution1: 读 -> while( ! feof(fp) ) -> print -> 读

solution2: while (读 != EOF) -> print

// === Prob:
#include <stdio.h>

int main()
{
    FILE *fp=NULL;
    int ch;

    fp = fopen("myfile.txt","w");
    fputs("abc", fp);  // {a, b, c, end-of-file}
    fclose(fp);

    fp = fopen("myfile.txt","r");
    if(fp == NULL)
        perror ("Error opening file");
        
    // fp: 指向 'c'
    // feof -> 读   -> 输出 
    //   feof(fp): return false -> 读 'c': fp 移到 end-of-file             -> 输出 'c'
    //   feof(fp): return false -> 读 end-of-file: p 不移, set EOF flag -> 输出 EOF
    //   feof(fp): return true  -> exit
    while( !feof(fp) )
    {
        ch = fgetc(fp);   
        printf("%c: %x\n", ch, ch);
    }
    fclose(fp);
}
a: 61
b: 62
c: 63
: ffffffff // EOF 的 hex 值 = 0xffffffff = -1
// === solution1:
#include <stdio.h>

int main()
{
    FILE *fp=NULL;
    int ch;

    fp = fopen("myfile.txt","w");
    fputs("abc", fp);  // {a, b, c, end-of-file}
    fclose(fp);

    fp=fopen("myfile.txt","r");
    if(fp == NULL)
        perror ("Error opening file");
        
    ch = getc ( fp ); 
    while( !feof(fp) )
    {
        printf("%c: %x\n", ch, ch);
        ch = getc(fp);    
    }
    fclose(fp);
}
// === solution2:
#include <stdio.h>

int main()
{
    FILE* fp = NULL;
    int ch;

    fp = fopen("myfile.txt", "w");
    fputs("abc", fp);  // {a, b, c, end-of-file}
    fclose(fp);

    fp = fopen("myfile.txt", "r");
    if (fp == NULL)
        perror("Error opening file");

    while ( (ch = fgetc(fp) ) != EOF)
        printf("%c: %x\n", ch, ch);

    if (fp)
        fclose(fp);
}
a: 61
b: 62
c: 63

7 Operations on files

remove
    erases a file

rename
    renames a file

tmpfile
    returns a pointer to a temporary file

(1) int remove(const char* filename)

(2) int rename(const char* oldFilename, const char* newFilename)

(3) FILE* tmpfile(void)

8 格式化 IO

8.1 从右到左: 将 data 按 格式化输出 write 到 stream / stdout / buf(char*) / buf

int fprintf (FILE* stream,           const char* format, ...)
int printf  (                        const char* format, ...)
int sprintf (char* buf,              const char* format, ...)
int snprintf(char* buf, size_t size, const char* format, ...)

Return

    传输的 字符数, 
    负数         ,    output error 

Note

(1) printf: 默认 无缓冲

(2) snprintf: size 不应该超过 caller 所控制的 buf 区间

(3) sprintf / snprintf

1) format 中: 最后一个 %s, 无 '\0' -> 加 '\0', 有 '\0' -> 保留; 其他 %s, 去 '\0'

2) 效率 高于 字符串操作函数

3) 更灵活: 可将 想要的结果 write到 指定 buf

#include <stdio.h>
int main()
{
    FILE *fp;
    fp = fopen( "file.txt", "w" );

    char name[20] = "xianyang";
    if( fp != NULL )
        fprintf( fp, "hello %s\n", name );

    fclose(fp); 
}
#include <stdio.h>

int main()
{
    char buf[10];
    char str1[] = {'a', 'b', 'c'};
    char str2[] = {'d', 'e', 'f'};

    sprintf(buf, "%.3s%.3s\n", str1, str2); 
    printf("%s", buf);

    //sprintf(buf, "%s%s", str1, str2);       //Don't do that!
}
abcdef

8.2 从 stream / stdin / buf 读 格式化输入指定变量

int fscanf(FILE* stream,    const char* format, ...)
int scanf (                 const char* format, ...)
int sscanf(const char* str, const char* format, ...)

Return

    成功匹配和赋值的个数(>= 0), success/第1个赋值就 matching failure   
    EOF                       , input fail 或 end-of-file

Note

[1] 格式字符串中 任何 单个 空白符消耗 输入中 所有 连续空白符, 好像 循环 isspace

空白符: 空格(" ") 换行("\n") Tab("\t")

[2] 遇 分隔符: 跳过

非 matching 格式的值: 从 input Buffer 跳出, 不跳过 也不取出

(1) scanf 4步曲

    例: 键盘输入 1 2 3

1) 键盘输入字符形式 存入 input Buffer

2) 控制符 %d 将字符 转化为相应格式 的 值 (10进制 123)

对 %d 而言, 空白符 是 data 分隔符

3) 通过 取地址 i(&i) 找到 变量 i 的地址

4) put 123 to 变量 i

Note

[1] 除非必要, 双引号内 不要用 非 input 控制符 ( 包括 \n: 不起换行的作用 ), 否则就是 自找麻烦; 而且 对用户而言, 输入越简单越好

[2] 多变量输入 时, input 控制符 之间 要用 空格 回车 Tab 分隔

[3] scanf/printf 中, 非 I/O 控制符原样 input/output

[4] 每个 scanf 前 clear stdin Buffer, 可从 无残留的 stdin Buffer 读取

#include <stdio.h>

// empty stdin_cache
void clear_stdin_cache()
{
    int ch;
    while( (ch = getchar() ) != '\n' && ch != EOF)
        ; 
}

int main()
{
    int a;
    int count;

    scanf("%d", &a); 
    printf("%d\n", a);

    // 清空 stdin 缓存
    // setbuf(stdin, NULL); // 等价于 clear_stdin_cache(); 
    clear_stdin_cache();

    count = scanf("a= %d", &a);
    if(count > 0)
        printf("a= %d\n", a);
}
image.png

(2) fscanf

[1] 每读完1项, 遇 分隔符 结束 => fp 指向 "hello " 时, 用 %s 只能取出 "hello", 空格 要用 %c 取出

[2] 与 fgets 区别: fgets 遇 空格(" ") 不结束

#include <stdio.h>

int main()
{
    int uVar;
    float fVar;
    char str[100];
    char ch;
    FILE* fp;

    fp = fopen("file.out", "w+");

    if (fp == NULL)
        printf("The file fscanf.out was not opened\n");
    else
    {
        fprintf(fp, "%s %d%f%c", "hello", 10, 3.14159, 'x');

        // set 指针至文件首
        fseek(fp, 0L, SEEK_SET);

        // 从文件中 读 数据
        fscanf(fp, "%s", str);      // Note: 遇 空格 结束, fp 移动到 空格 的 next 位置

        int pos = ftell(fp); 
        printf("%d\n", pos);        // 5: 空格位置

        fscanf(fp, "%2d", &uVar);  // 遇 空格 (对 %s %d 来说是 分隔符): 跳过
        fscanf(fp, "%f", &fVar);
        fscanf(fp, "%c", &ch);

        printf("%s\n", str);
        printf("%d\n", uVar);
        printf("%f\n", fVar);
        printf("%c\n", ch);

        fclose(fp);
    }
}
5
hello
10
3.141590
x

(3) sscanf: %*s: 过滤掉 对应匹配的 %s

#include <stdio.h>
int main()
{
    char buf[50];
    
    // 给定字符串 "hello, world", 仅保留 "world"
    sscanf("hello, world", "%*s%s", buf); // 过滤掉 "hello,"  
    printf("%s\n", buf); //world
}

9 非格式化 I/O: 字符处理函数

9.1 fputc / putc / putchar: Writes a character to stream / stream / stdout + advances position indicator of stream

return
    写入的 字符, success
    EOF,         write error-> set Error Flag

(1) int fputc(int ch, FILE* stream)

(2) int putc (int ch, FILE* stream)

(3) int putchar(int ch)

    fputc / putc 仅 1 点不同
        某些 库中, putc 用 宏实现

        putahcr() <=> getc( stdout )

9.2 fgetc / getc / getchar: Read a character from stream/stream/stdin

return
    所读到的 character 
        提升为 int 值, 以 `include EOF 值`, success
            `file position indicator` 移到 `next character`
        
    EOF, 遇 end-of-file / read Error 
      => `sets EOF/Error Flags => feof() / ferror() == true

Note

里奇开发 C 时, 没 terminal input 的概念, 输入 都是从 文件 读取

文件 为单位, 最后1行 结束后, 还要用 end-of-file 来标志 文件结束

    => 

遇 newline("\n", 回车 认为 == "\n"), 程序才认为 输入 ( scanf getchar gets 等 ) 结束

(1) int fgetc(FILE* stream );

(2) int getc(FILE* stream );

(3) int getchar ( void );

    fgetc / getc 仅 1 点不同: 某些 库中, getc 用 宏实现
    
    getchar() <=> getc(stdin)
        实现 maybe
        #define getchar() getc(stdin)

fgetc() / getc() 经典用法

int c; // (1) note: int, not char, required to handle EOF

// (2) standard C I/O file reading loop
while ( (c = fgetc(fp) ) != EOF ) // 用 getc 也可
{                                       
    putchar(c);
}

if ( ferror(fp) ) 
{
    puts("I/O error when reading");
} 
else if ( feof(fp) ) 
{
    puts("End-of-file reached successfully");
}

getchar: 回车后, '\n' 及 之前字符 放 stdin buf, getchar 才开始 从 stdin buf 读 1 个字符, 并 回显 到屏幕

EOF: end of file

Windows/Unix 值都是 -1

1) 可作 文本文件 结束标志

    文本文件 data 以 `字符 的 ASCII 码值 ( 0-127 ) ` 存放,
    无 -1

2) 不可作 二进制文件 结束标志 -> feof(fp) 可判 二进制/文本 文件 是否结束

    二进制文件 有 -1 
#include <stdio.h>

//文本文件 复制到 另一个文件
void filecopy( FILE *fpin, FILE *fpout )
{
    int ch;
    
    ch = getc ( fpin );   
    while ( !feof( fpin ) ) 
    {
        putc( ch, fpout ); 
        ch = getc ( fpin ); // fp indicator 指向 EOF -> getc -> return EOF + set feof -> exit while
    } 
}

int main ()
{
    FILE*fpin,*fpout;
    fpin = fopen ("file1.dat","r"); 
    fpout = fopen ("file2.dat","w"); 
    filecopy( fpin,fpout ); 
    fclose ( fpin );
    fclose ( fpout ); 
}
image.png
文件1 依次读取:
a(97) b(98) \n(10) c(99) -1(end-of-file)

=> windows: 行尾 只有 '\n', 可认为 下一行首 '\r' 被 覆盖

windows 下 输入 EOF 的方法:回车 -> ctrl + z -> 回车

// 经典例子: copy input to output 
#include <stdio.h>
#include <ctype.h>

int main()
{
    int ch;

    while( ( ch = getchar() ) != EOF )
          putchar( tolower( ch ) );
}

9.3 fputs / puts: Write C风格字符串 to stream / stdout

Note:

[1] not Write '\0'

[2] fputs/puts: (file)不加 / (stdout)加 newline("\n")

Return 
    >= 0, success
    EOF,  error -> + sets Error Flag

(1) int fputs(const char* buf, FILE* stream);

(2) int puts (const char* buf);

9.4 fgets / gets: 从 stream/stdin Read a line(1行)

Note:

[1] fgets/gets: newline copied into buf / 去 newline ( 遇 newline, not copied into buf )

[2] 加 '\0'

return
    buf,  success
    NULL, end-of-file 或 read error -> + `sets EOF/Error Flags

(1) char* fgets(char* buf, int n, FILE* stream)

读 `stream`, until

    1) `读 n-1 个字符`
    
    2) 遇 newline
    3) 遇 end-of-file 

    whichever happens first

(2) char* gets (char* buf) // stdin

读 `stdin`, until
    1) 遇 newline
    2) 遇 end-of-file 

    whichever happens first
#include <stdio.h>
int main()
{
    char str[50];
    gets(str);
    printf("%s", str);
}

相关文章

  • 1. C 标准库

    1.C 标准库 – | 菜鸟教程——string.h 2.C 标准库 – | 菜鸟教程——stdio.h 3....

  • C标准库——

    stdio.h 头文件定义了三个变量类型,一些宏和各种函数来执行输入和输出。 库函数 size_t 这是无符...

  • C 标准库 - stdio.h

    I/O 函数 Return value 总结, 字符处理函数 除外 (1) returnType 为 整型/siz...

  • stdlib.h和stdio.h有什么区别

    C语言标准库 stdlib.h和stdio.h有什么区别 一、定位不同。 1、stdlib.h是standard...

  • Boolan C++标准库 第一周

    C++标准库 第一讲 一、认识headers、版本 1.C++标准库 vs STL C++标准库大于STL(标准...

  • C语言入门基础之输入和输出

    标准输入和标准输出 在C语言里要使用标准输入和标准输出必须包含stdio.h头文件,常用的标准输出和标准输入函数是...

  • 博览网:STL与泛型编程第一周笔记

    1.C++标准库和STL C++标准库以header files形式呈现: (1)C++标准库的header fi...

  • C语言概述基础

    1、#include C预处理器指令 头文件 stdio.h 包含了标准输入/输出函数,使用需要C预处理指令,在<...

  • 系统编程:标准IO和文件IO

    一、概述 标准IO:标准I/O是ANSI C建立的一个标准I/O模型,是一个标准函数包和stdio.h头文件中的定...

  • Boolan C++ STL与泛型编程_1

    c++标准库--体系结构与内核分析 主要内容: 本节主要对c++标准库学习的4个阶段,c++标准库和新旧式C的头文...

网友评论

      本文标题:C 标准库 - stdio.h

      本文链接:https://www.haomeiwen.com/subject/wrqhwrtx.html