Backward file reader
You will learn or practice how to:
- Program with files.
- Program with structs to encapsulate data.
- Buffer data read from a file to improve program performance.
- Apply test-driven development (TDD).
You will write code to read files in backwards. You will need to design your own
struct to fullfill the requirements of this homework. See the Requirements table below for more detail on what you will create.
A common use of a backwards file reader is to display recent events from the log file of a website. These files can be very large and difficult to inspect by hand, but reading the file backwards to forwards allows for more easy processing of logs. In this assignment you will implement such a reader to read files backwards.
Generally, file I/O is a very expensive operation in any program and can be the bottle neck which prevents better performance. In this assignment, you will help to alleviate performance issues by buffering file I/O operations into a custom structure, and then use that structure to read in a file backwards and display it line by line.
For this assignment you will need to use several new functions for interacting with files. A complete description of these functions can be found by typing
man function_name but here is a brief description of each:
FILE* fopen(const char* filename, const char* mode)- This function opens the file at filename with mode mode and returns a FILE struct which you can use to interact with the file. The modes you may need for this assignment are as follows:
- w - used to open a file for writing, this mode deletes a file's contents if it has any or creates a new file
- r - used to open a file for reading
int fclose(FILE* stream)- This function is used to close a file you have opened with
fopenso that all resources relating to the file are freed. You must have exactly one call to
fclosefor each call to
int fseek(FILE* stream, long offset, int whence)- This function moves where in the file you are currently reading from/writing to. Stream is the FILE structure you obtained from
fopen, offset is the distance to move (can be positive, negative, or zero) and whence is a constant describing where you should move relative to. Whence can be one of three constant values:
SEEK_SET- seek to an absolute position from the beginning of the file
SEEK_CUR- seek from the current location in the file
SEEK_END- seek from the end of the file
long ftell(FILE* stream)- This function returns your current position in the file measured from the start of the file.
size_t fread(void* dest, size_t size, size_t count, FILE* stream)- This function reads in count elements of size size from stream and copies them into the buffer provided to dest. For example if you wanted to read in 10 ints from a file you might do the following:
FILE* fp = fopen("ints_data.txt", "r"); int *array = malloc(sizeof(*array) * 10); fread(array, sizeof(*array), 10, fp); fclose(fp);
This assignment includes a warm-up exercise to help you get ready. This accounts for 10% of your score for HW10. Scoring will be relatively light, but the usual base requirements apply.
The structure of the warmup.c file is described in the Requirements table below. You should write your own warmup.c.
In a hurry, and don't need the practice? This warm-up is here to help you learn what you need to succeed on the rest of this assignment—not to add additional work. Therefore, we give you an option. Those who feel that they do not need the practice may "opt out". by modifying warmup.c so that it does nothing but print the following message exactly and then exit:
I already know this and do not need to practice.
If you do that, then your score for HW10 will be based solely on the rest of this assignment. If you leave the warmup.c undone, if you do not turn in a warmup.c, or if the message it prints does not match perfectly, then you will receive 0 for the warmup portion of this assignment (10%).
Doing the assignment
264get HW10 to fetch the starter code.
Use test-driven development to complete this assignment incrementally.
- Your submission must contain each of the following files, as specified:
file contents backwards_file.h types
structto hold all information you will need in order to read a file backwards and buffer a specific amount.
- You may include whatever fields you think are necessary to complete this assignment.
- Hint: You will want to store a file pointer to the open file.
You may add additional types and/or constants to backwards_file.h, if you wish. backwards_file.c functions
create file wrapper(char✶ filename, char✶✶ a error)→ return type: FileWrapper ✶the file
- OPTIONAL: Return
NULLin case of an error (e.g., unable to open file).
read line(FileWrapper✶ fw, char✶✶ a error)→ return type: unsigned char ✶Return the next line from the back of the file.
- You will allocate the required memory for the string you read from the line.
- You may assume the caller is responsibible for freeing the returned line.
you failed to open the filethere was an error reading the file.
- When a line ends with a '\n', include it in the string that is returned. For the last line in a file that doesn't end in '\n', return as is, without the '\n'.
- The characters within each line should be in the same order they were in the file.
- The behavior is similar in spirit to the
taccommand in bash. You might find it useful to try that command or read its man page.
- OPTIONAL: After all lines of the file have been returned,
any subsequent calls to
read_line(…)should return NULL. To distinguish from file errors, set
*a_error = NULL.
free wrapper(FileWrapper✶ fw)→ return type: voidFree all heap allocated memory assoicated with the
main(int argc, char✶ argv)→ return type: int
- This is the same as in previous assignments.
- Tests must result in 100% code coverage.
expected.txt test output
- This is the same as in previous assignments.
- If you are using miniunit.h, you may simply redirect the output of your working tests to expected.txt to create this.
print contents of file(char✶ filename)→ return type: voidRead every byte in a file and print it to
- This should not call
print first n chars in file(char✶ filename, int n, char✶✶ a error)→ return type: voidRead the first n bytes in a file and print them to
- This should not call
- If there are <n bytes in the file, then print the entire contents of the file.
get first line of file(char✶ filename, char✶✶ a error)→ return type: char✶Read the first line of a file and return it as a string on the heap.
- This should call
- Caller is responsible for freeing the memory.
- For all functions that take a parameter called
a_error, in case of any error with the file (e.g., file not found, unreadable, etc.), set
*a_errorto the error message string returned by
- OPTIONAL: Set
*a_error = NULLif there was no file error.
- OPTIONAL: Set
- For the main part of this homework (excluding the warmup):
- Do not read any byte more than once.
- You must read the file in fixed-size chunks.
- Pick a buffer size.
- It could be a constant in your backwards_file.h (e.g., 128 bytes)
- Alternatively, it may be dynamically determined in
create_file_wrapper(…)(e.g., based on the file size).
- Buffer size must not be 1 or the size of the file.
- When calling
fread(…), read exactly
buffer_sizebytes at a time.
- Your last call to
fread(…)(e.g., when reading the very beginning of the file) may read a smaller number of bytes.
- Buffer size may not be <8 bytes or >1024 bytes.
- Do not read one byte at a time .
- Do not read the entire file
- “line” means a sequence of bytes that begins at the beginning of a file or immediately after
'\n'and ends with a
- Make no assumptions on the size of the file or the size of the
- Your structure may have any fields you wish as long as it is sufficient to complete the assignment.
- OPTIONAL: You may create an alias for unsigned char like this:
typedef unsigned char uchar;and then substitute
ucharin place of
unsigned charin your code and the header file.
Only the following external header files, functions, and symbols are
allowed. You may use
stdoutin either one (or both).
header functions/symbols allowed in… stdbool.h
EOF. Feel free to ask if there is something you would like to use.
- OPTIONAL: You may add const to any parameter in the header file (or anything else).
- Submissions must meet the code quality standards and the course policies on homework and academic integrity.
To submit HW10, type
264submit HW10 backwards_file.c backwards_file.h test_backwards_file.c expected.txt warmup.c miniunit.h clog.h
from inside your hw10 directory.
If your code does not depend on miniunit.h or clog.h, those may be omitted. If your tests rely on text files, submit them. In general, you should submit everything needed to compile and your code and run your tests.
The pre-tester for HW10 has been released and is ready to use.
How much work is this?
|3/21/2019||Fixed warmup functions|
|3/22/2019||Removed requirement about not modifying backwards_file.h; clarified: do not use
|3/23/2019||Removed the reference to diff testing. Miniunit is preferred (but still optional). Minor clarifications.|
|3/25/2019||Specification for buffer size was expanded; deadline extended|
|3/26/2019||Corrected table of allowed functions/symbols. There is no need to use
Added a few OPTIONAL suggestions to fill holes in the specification. Most came up in
response to questions on Piazza or in class. These will not be tested.
No bonus credit will be given.