{"id":20843826,"url":"https://github.com/num30/cachedreader","last_synced_at":"2026-04-16T13:42:14.520Z","repository":{"id":57656697,"uuid":"458323959","full_name":"num30/cachedreader","owner":"num30","description":"io.Reader that you can read twice","archived":false,"fork":false,"pushed_at":"2022-02-12T14:43:39.000Z","size":10,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-01-19T03:18:24.043Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/num30.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-02-11T20:00:22.000Z","updated_at":"2022-06-30T18:29:31.000Z","dependencies_parsed_at":"2022-08-26T05:11:52.983Z","dependency_job_id":null,"html_url":"https://github.com/num30/cachedreader","commit_stats":null,"previous_names":["testhub-io/cachedreader"],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/num30%2Fcachedreader","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/num30%2Fcachedreader/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/num30%2Fcachedreader/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/num30%2Fcachedreader/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/num30","download_url":"https://codeload.github.com/num30/cachedreader/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243205245,"owners_count":20253425,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-18T02:07:27.285Z","updated_at":"2025-12-26T14:02:15.458Z","avatar_url":"https://github.com/num30.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Cached Reader\nCached Reader is an implementation of a reader that could be re-read from the beginning.\nOne of the scenarios is when you need to verify the file header or request data by examining content at the beginning of the stream.\n\n## Install \n``` \n  go get github.com/testhub-io/cachedreader\n```\n\n## Example 1. Minimal example \n\n``` go\npackage main\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/testhub-io/cachedreader\"\n)\n\nfunc main() {\n\tvar str = []byte(\"the quick brown fox jumps over the lazy dog\")\n\tr := cachedreader.NewCachedReader(bytes.NewReader(str)) // create cached reader\n\tthe := make([]byte, 3)\n\t_, err := r.Read(the) // Read first 3 bytes\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(string(the)) // print \"the\"\n\n\tb, err := io.ReadAll(r)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(string(b)) // print whole string\n}\n```\n\n## Example 2. Check if http request body is a valid tar.gz file and store it \n\n``` go\n// http handler \nfunc storeFile(w http.ResponseWriter, req *http.Request) {\n\n\tbufReader := cachedreader.NewCachedReader(req.Body)\n\n\tuncompressedStream, err := gzip.NewReader(bufReader) // uncompress the gzip stream\n\tif err != nil {\n\t\tw.Write([]byte(fmt.Sprintf(\"Failed to read gz stream. %v\", err)))\n\t\treturn\n\t}\n\n\ttr := tar.NewReader(uncompressedStream) // create tar reader\n\t_, err = tr.Next() // read the file header\n\tif err != nil { // if error then stream is no a valid tar file\n\t\tw.Write([]byte(fmt.Sprintf(\"Not a tar.gz stream. %v\", err)))\n\t\treturn\n\t}\n\tbufReader.Reset() // reset reader to the biggining\n\n\tout, err := os.Create(\"filename.tar.gz\")\n\tif err != nil {\n\t\tw.Write([]byte(fmt.Sprintf(\"Error creating file. %v\", err)))\n\t\treturn\n\t}\n\tdefer out.Close() \n\n\tio.Copy(out, bufReader) // write content to a file form the beginning of the stream\n}\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnum30%2Fcachedreader","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnum30%2Fcachedreader","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnum30%2Fcachedreader/lists"}