{"id":15010668,"url":"https://github.com/clj-commons/byte-streams","last_synced_at":"2026-04-07T04:31:41.414Z","repository":{"id":9185704,"uuid":"10989040","full_name":"clj-commons/byte-streams","owner":"clj-commons","description":"A Rosetta stone for JVM byte representations","archived":false,"fork":false,"pushed_at":"2025-03-30T10:35:54.000Z","size":1198,"stargazers_count":430,"open_issues_count":6,"forks_count":32,"subscribers_count":15,"default_branch":"master","last_synced_at":"2026-01-12T02:36:09.871Z","etag":null,"topics":["bytes","clojure","streams"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/clj-commons.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.adoc","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2013-06-27T06:16:29.000Z","updated_at":"2025-12-20T12:13:54.000Z","dependencies_parsed_at":"2024-06-18T15:37:20.887Z","dependency_job_id":"bd03cbab-2bf9-4a79-84e8-da73529b58ed","html_url":"https://github.com/clj-commons/byte-streams","commit_stats":{"total_commits":231,"total_committers":19,"mean_commits":"12.157894736842104","dds":"0.38528138528138534","last_synced_commit":"a88b09b6b1c736ac8c0e9ea938f30c2e476d3e71"},"previous_names":["ztellman/byte-streams"],"tags_count":49,"template":false,"template_full_name":null,"purl":"pkg:github/clj-commons/byte-streams","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clj-commons%2Fbyte-streams","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clj-commons%2Fbyte-streams/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clj-commons%2Fbyte-streams/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clj-commons%2Fbyte-streams/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/clj-commons","download_url":"https://codeload.github.com/clj-commons/byte-streams/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clj-commons%2Fbyte-streams/sbom","scorecard":{"id":291853,"data":{"date":"2025-08-11","repo":{"name":"github.com/clj-commons/byte-streams","commit":"37a3357870014715a94b22066395b1689a04d87d"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.9,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":2,"reason":"Found 3/11 approved changesets -- score normalized to 2","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 23 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-17T18:27:56.652Z","repository_id":9185704,"created_at":"2025-08-17T18:27:56.652Z","updated_at":"2025-08-17T18:27:56.652Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31500397,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-07T03:10:19.677Z","status":"ssl_error","status_checked_at":"2026-04-07T03:10:13.982Z","response_time":105,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["bytes","clojure","streams"],"created_at":"2024-09-24T19:35:17.009Z","updated_at":"2026-04-07T04:31:41.392Z","avatar_url":"https://github.com/clj-commons.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Clojars Project](https://img.shields.io/clojars/v/org.clj-commons/byte-streams.svg)](https://clojars.org/org.clj-commons/byte-streams)\n[![cljdoc badge](https://cljdoc.org/badge/org.clj-commons/byte-streams)](https://cljdoc.org/d/org.clj-commons/byte-streams)\n[![CircleCI](https://circleci.com/gh/clj-commons/byte-streams.svg?style=svg)](https://circleci.com/gh/clj-commons/byte-streams)\n\n![](docs/header.jpg)\n\nJava has a lot of different ways to represent a stream of bytes.  Depending on the author and age of a library, it might use `byte[]`, `InputStream`, `ByteBuffer`, or `ReadableByteChannel`.  If the bytes represent strings, there's also `String`, `Reader`, and `CharSequence` to worry about.  Remembering how to convert between all of them is a thankless task, made that much worse by libraries which define their own custom representations, or composing them with Clojure's lazy sequences and stream representations.\n\nThis library is a Rosetta stone for all the byte representations Java has to offer, and gives you the freedom to forget all the APIs you never wanted to know in the first place.  Complete documentation can be found [here](https://cljdoc.org/d/org.clj-commons/byte-streams).\n\n### Usage\n\nLeiningen:\n```clojure\n[org.clj-commons/byte-streams \"0.3.4\"]\n```\n\ndeps.edn:\n```clojure\norg.clj-commons/byte-streams {:mvn/version \"0.3.4\"}\n```\n\n### Converting types\n\nTo convert one byte representation to another, use `convert`:\n\n```clojure\nclj-commons.byte-streams\u003e (convert \"abcd\" java.nio.ByteBuffer)\n#\u003cHeapByteBuffer java.nio.HeapByteBuffer[pos=0 lim=4 cap=4]\u003e\nclj-commons.byte-streams\u003e (convert *1 String)\n\"abcd\"\n```\n\n`(convert data to-type options?)` converts, if possible, the data from its current type to the destination type.  This destination type can either be a Java class or a Clojure protocol.  However, since there's no direct route from a string to a byte-buffer, under the covers `convert` is doing whatever it takes to get the desired type:\n\n```clojure\nclj-commons.byte-streams\u003e (conversion-path String java.nio.ByteBuffer)\n([java.lang.String [B]\n [[B java.nio.ByteBuffer])\n```\n\nWhile we can't turn a string into a `ByteBuffer`, we can turn a string into a `byte[]`, and `byte[]` into a `ByteBuffer`.  When invoked, `convert` will choose the minimal path along the graph of available conversions.  Common conversions are exposed via `to-byte-buffer`, `to-byte-buffers`, `to-byte-array`, `to-input-stream`, `to-readable-channel`, `to-char-sequence`, `to-string`, and `to-line-seq`.\n\nEvery type can exist either by itself, or as a sequence.  For instance, we can create an `InputStream` representing an infinite number of repeated strings:\n\n```clojure\nclj-commons.byte-streams\u003e (to-input-stream (repeat \"hello\"))\n#\u003cInputStream byte_streams.InputStream@3962a02c\u003e\n```\n\nAnd then we can turn that into a lazy sequence of `ByteBuffers`:\n\n```clojure\nclj-commons.byte-streams\u003e \n  (take 2 (convert *1\n                   (seq-of java.nio.ByteBuffer)\n                   {:chunk-size 128}))\n(#\u003cHeapByteBuffer java.nio.HeapByteBuffer[pos=0 lim=128 cap=128]\u003e\n #\u003cHeapByteBuffer java.nio.HeapByteBuffer[pos=0 lim=128 cap=128]\u003e)\n```\n\nNotice that we describe a sequence of a type as `(seq-of type)`, and that we've passed a map to `convert` describing the size of the `ByteBuffers` we want to create.  Available options include:\n\n* `:chunk-size` - the size in bytes of each chunk when converting a stream into a lazy seq of discrete chunks, defaults to `4096`\n* `:direct?` - whether any `ByteBuffers` which are created should be [direct](http://stackoverflow.com/a/5671880/228387), defaults to `false`\n* `:encoding` - the character set for any strings we're encoding or decoding, defaults to `\"UTF-8\"`\n\nTo create a [Manifold stream](https://github.com/clj-commons/manifold/), use `(stream-of type)`.  To convert a core.async channel, convert it using `manifold.stream/-\u003esource`.\n\n### Custom conversions\n\nWhile there are conversions defined for all common byte types, this can be extended to other libraries via `def-conversion`:\n\n```clojure\n;; a conversion from byte-buffers to my-byte-representation\n(def-conversion [ByteBuffer MyByteRepresentation]\n  [buf options]\n  (buffer-\u003emy-representation buf options))\n\n;; everything that can be converted to a ByteBuffer is transitively fair game now\n(convert \"abc\" MyByteRepresentation)\n```\n\nThis mechanism can even be used for types unrelated to byte streams, if you're feeling adventurous.\n\n### Transfers\n\nSimple conversions are useful, but sometimes we'll need to do more than just keep the bytes in memory.  When you need to write bytes to a file, network socket, or other endpoints, you can use `transfer`.\n\n```clojure\nclj-commons.byte-streams\u003e (def f (File. \"/tmp/salutations\"))\n#'clj-commons.byte-streams/f\nclj-commons.byte-streams\u003e (transfer \"hello\" f {:append? false})\nnil\nclj-commons.byte-streams\u003e (to-string f)\n\"hello\"\n```\n\n`(transfer source sink options?)` allows you pipe anything that can produce bytes into anything that can receive bytes, using the most efficient mechanism available.  Custom transfer mechanisms can also be defined:\n\n```clojure\n(def-transfer [InputStream MyByteSink]\n  [stream sink options]\n  (send-stream-to-my-sink stream sink))\n```\n\n### Some utilities\n\n`print-bytes` will print both hexadecimal and ascii representations of a collection of bytes:\n\n```clojure\nclj-commons.byte-streams\u003e (print-bytes (-\u003e #'print-bytes meta :doc))\n50 72 69 6E 74 73 20 6F  75 74 20 74 68 65 20 62      Prints out the b\n79 74 65 73 20 69 6E 20  62 6F 74 68 20 68 65 78      ytes in both hex\n20 61 6E 64 20 41 53 43  49 49 20 72 65 70 72 65       and ASCII repre\n73 65 6E 74 61 74 69 6F  6E 73 2C 20 31 36 20 62      sentations, 16 b\n79 74 65 73 20 70 65 72  20 6C 69 6E 65 2E            ytes per line.\n```\n\n`(compare-bytes a b)` will return a value which is positive if `a` is lexicographically first, zero if they're equal, and negative otherwise:\n\n```clojure\nclj-commons.byte-streams\u003e (compare-bytes \"abc\" \"abd\")\n-1\n```\n\n`bytes=` will return true if two byte streams are equal, and false otherwise.\n\n`conversion-path` returns all the intermediate steps in transforming one type to another, if one exists:\n\n```clojure\n;; each element is a conversion pair of to/from\nclj-commons.byte-streams\u003e (conversion-path java.io.File String)\n([java.io.File java.nio.channels.ReadableByteChannel]\n [#'byte-streams/ByteSource java.lang.CharSequence]\n [java.lang.CharSequence java.lang.String])\n\n;; but if a conversion is impossible...\nclj-commons.byte-streams\u003e (conversion-path java.io.OutputStream java.io.InputStream)\nnil\n```\n\n`possible-conversions` returns a list of possible conversion targets for a type.\n\n```clojure\nclj-commons.byte-streams\u003e (possible-conversions String)\n(java.lang.String java.io.InputStream java.nio.DirectByteBuffer java.nio.ByteBuffer (seq-of java.nio.ByteBuffer) java.io.Reader java.nio.channels.ReadableByteChannel [B java.lang.CharSequence)\n```\n\n`byte-streams/optimized-transfer?` returns true if there is an optimized transfer method for two types:\n\n```clojure\nclj-commons.byte-streams\u003e (optimized-transfer? String java.io.File)\ntrue\n```\n\n### Deprecation notice\n\nThere exists an older, top-level namespace called just `byte-streams` that has been deprecated. Top-level namespaces can cause problems, particularly with Graal. Please switch to `clj-commons.byte-streams` in all your requires.\n\n### License\n\nCopyright © 2014 Zachary Tellman\n\nDistributed under the [MIT License](http://opensource.org/licenses/MIT)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclj-commons%2Fbyte-streams","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fclj-commons%2Fbyte-streams","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclj-commons%2Fbyte-streams/lists"}