我理解C的一般概念以及如何制作日志文件。读/写文件等。
我关注的是以下格式:
[![在此处输入图像说明] [1]] [1]
我现在已经完成了一个很好的块,但是我担心在第一条记录之后如何附加到我的日志文件中。我递增文件的记录计数(在前2个字节中)并在其后写入第一个记录。然后,我将如何设置将第2 /第3 / etc记录添加到彼此之后?
//confirm a file exists in the directory
bool fileExists(const char* file)
{
struct stat buf;
return (stat(file, &buf) == 0);
}
int rightBitShift(int val, int space)
{
return ((val >> space) & 0xFF);
}
int leftBitShift(int val, int space)
{
return (val << space);
}
int determineRecordCount(char * logName)
{
unsigned char record[2];
FILE *fp = fopen(logName, "rb");
fread(record, sizeof(record), 1, fp);
//display the record number
int recordNum = (record[0] << 8) | record[1];
recordNum = recordNum +1;
return (recordNum);
}
void createRecord(int argc, char **argv)
{
int recordNum;
int aux = 0;
int dst;
char* logName;
char message[30];
memset(message,' ',30);
//check argument count and validation
if (argc == 7 && strcmp("-a", argv[2]) ==0 && strcmp("-f", argv[3]) ==0 && strcmp("-t", argv[5]) ==0)
{
//aux flag on
aux = 1;
logName = argv[4];
strncpy(message, argv[6],strlen(argv[6]));
}
else if (argc == 6 && strcmp("-f", argv[2]) ==0 && strcmp("-t", argv[4]) ==0)
{
logName = argv[3];
strncpy(message, argv[5],strlen(argv[5]));
}
else
{
printf("Invalid Arguments\n");
exit(0);
}
//check if log exists to get latest recordNum
if (fileExists(logName))
{
recordNum = determineRecordCount(logName);
printf("%i\n",recordNum);
}
else
{
printf("Logfile %s not found\n", logName);
recordNum = 1;
}
//Begin creating record
unsigned char record[40]; /* One record takes up 40 bytes of space */
memset(record, 0, sizeof(record));
//recordCount---------------------------------------------------------------------
record[0] = rightBitShift (recordNum, 8); /* Upper byte of sequence number */
record[1] = rightBitShift (recordNum, 0); /* Lower byte of sequence number */
//get aux/dst flags---------------------------------------------------------------
//get date and time
time_t timeStamp = time(NULL);
struct tm *date = localtime( &timeStamp );
if (date->tm_isdst)
dst = 1;
record[2] |= aux << 7; //set 7th bit
record[2] |= dst << 6; //set 6th
//timeStamp-----------------------------------------------------------------------
record[3] |= rightBitShift(timeStamp, 24);//high byte
record[4] |= rightBitShift(timeStamp, 16);
record[5] |= rightBitShift(timeStamp, 8);
record[6] |= rightBitShift(timeStamp, 0); //low byte
//leave bytes 7-8, set to 0 -----------------------------------------
record[7] = 0;
record[8] = 0;
//store message--------------------------------------------
strncpy(&record[9], message, strlen(message));
//write record to log-----------------------------------------------------------------
FILE *fp = fopen(logName, "w+");
unsigned char recordCount[4];
recordCount[0] = rightBitShift (recordNum, 8); /* Upper byte of sequence number */
recordCount[1] = rightBitShift (recordNum, 0); /* Lower byte of sequence number */
recordCount[2] = 0;
recordCount[3] = 0;
fwrite(recordCount, sizeof(recordCount), 1, fp);
fwrite(record, sizeof(record), 1, fp);
fclose(fp);
printf("Record saved successfully\n");
}
答案 0 :(得分:1)
注意:在C之前,我从来没有这样做,带着一粒盐。
这是一种非常具体的二进制格式,其中每个位都被精确考虑。它使用Least-Significant-Bit numbering scheme (LSB 0),其中位从7到0编号。
指定&#34;高位字节&#34;首先表示此格式为big-endian。最重要的位首先出现。这就像我们写下我们的数字一样,四千三百二十一是4321. 1234将是小尾数。例如,记录数和序列都是16位大端数。
最后,checksum是从记录的其余部分计算的数字,以验证传输中没有错误。规范定义了如何进行校验和。
您的工作是精确复制此格式,可能使用fixed-sized types found in stdint.h或unsigned char
。例如,序列可以是uint16_t
或unsigned char[2]
。
生成记录的函数可能有这样的签名:
unsigned char *make_record( const char *message, bool aux );
用户只需向您提供消息和辅助标志。其余的你可以通过功能弄清楚。您可能决定让它们传递时间戳和顺序。重点是,函数只需要传递数据,它负责格式化。
这种字节顺序意味着你不能写出整数,它们可能是错误的大小或错误的字节顺序。这意味着必须先序列化任何多字节整数,然后才能将它们写入记录。 This answer covers ways to do that并且我将使用this answer中的那些,因为它们更方便了。
#include <stdio.h>
#include <stdint.h>
#include <time.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
unsigned char *make_record( const char *message, bool aux ) {
// Allocate and zero memory for the buffer.
// Zeroing means no risk of accidentally sending garbage.
unsigned char *buffer = calloc( 40, sizeof(unsigned char) );
// As we add to the buffer, pos will track the next byte to be written.
unsigned char *pos = buffer;
// I decided not make the user responsible for
// the sequence number. YMMV.
static uint16_t sequence = 1;
pos = serialize_uint16( pos, sequence );
// Get the timestamp and DST.
time_t timestamp = time(NULL);
struct tm *date = localtime( ×tamp );
// 2nd row is all flags and a bunch of 0s. Start with them all off.
uint8_t flags = 0;
if( aux ) {
// Flip the 7th bit on.
flags |= 0x80;
}
if( date->tm_isdst ) {
// Flip the 6th bit on.
flags |= 0x40;
}
// That an 8 bit integer has no endianness, this is to ensure
// pos is consistently incremented.
pos = serialize_uint8(pos, flags);
// I don't know what their timestamp format is.
// This is just a guess. It's probably wrong.
pos = serialize_uint32(pos, (uint32_t)timestamp);
// "Spare" is all zeros.
// The spec says this is 3 bytes, but only gives it bytes
// 7 and 8. I'm going with 2 bytes.
pos = serialize_uint16(pos, 0);
// Copy the message in, 30 bytes.
// strncpy() does not guarantee the message will be null
// terminated. This is probably fine as the field is fixed width.
// More info about the format would be necessary to know for sure.
strncpy( pos, message, 30 );
pos += 30;
// Checksum the first 39 bytes.
// Sorry, I don't know how to do 1's compliment sums.
pos = serialize_uint8( pos, record_checksum( buffer, 39 ) );
// pos has moved around, but buffer remains at the start
return buffer;
}
int main() {
unsigned char *record = make_record("Basset hounds got long ears", true);
fwrite(record, sizeof(unsigned char), 40, stdout);
}
此时我的专业知识已经筋疲力尽,我以前从未这样做过。我很感激大家修复编辑中的小错误,并建议在评论中更好的方法,比如如何处理时间戳。也许其他人可以在另一个答案中介绍如何进行1恭维校验和。
答案 1 :(得分:0)
由于字节由8位(从0到7)组成,因此您可以按照规范中的要求使用按位运算来修改它们。查看一般信息(https://en.wikipedia.org/wiki/Bitwise_operations_in_C)。作为预览,您可以使用&gt;&gt;或&lt;&lt;运算符确定要修改哪个位,并使用逻辑运算符|和&amp;设定它的价值观。