Repository: ouch-org/ouch (language: rust)

Issue:
Support `.7z`
The title sums up the first part of the request pretty well, 7z is a pretty popular archive format, but 7z supports several different compression formats it supports, so I think it would also be good to add an option like `--format`/`-f` to specify a compression format independently of the file name, which would be useful in general too


Discussion / hints:
About --format, it's related to #134.

(I think this issue can focus more on 7z.)
The only crate I found is https://lib.rs/crates/rust7z, docs are failing and seems unmaintained
https://lib.rs/crates/lzma-rs does say it might also implement 7z in the future, its something we can wait for
otherwise we would have to implement it ourselves using some lzma crate
I'd rather wait for other crates than implement it by ourselves (unless someone gets really interested in doing so...), Rust ecosystem is always growing, so I bet that someone will do it (from scratch or by fixing existing crates).

Will keep this open indefinitely, in hope it will become possible.
https://crates.io/crates/sevenz-rust may be worth watching. Doesn't look like it supports compression yet.
Can you not maybe rely upon and call out to the 7z/7z.exe shell command for 7z functionality perhaps?  I believe 7z also supports RAR archives as well, so that would give you a free solution to the "Support RAR" issue request as well, I think.  Or is that sorta thing not very convenient to do from Rust?  (I'ma Python guy,  so I'm afraid I know little about Rust beyond how to build / install existing Rust apps.  On Python, I use the `subprocess` library to call shell commands.  I just kinda assumed most modern languages have similar functionality available.)
Calling a binary works, but it can make shipping more difficult, currently Ouch does not require any other binary to be installed, but there are a couple of alternative tools that approach it this way. We'd need to put this as a dependency, but then Ouch wouldn't be shippable to something that 7z isn't shipped too. 

Invoking a binary also runs into some other problems I explained in finer detail at [#152](https://github.com/ouch-org/ouch/issues/152#issuecomment-968137837), regarding stream encoding and decoding, and also error handling, I think that error treatment in Ouch is very satisfactory, we can generate a custom message for almost all steps.

When I consider all of these I'd say it's not worth it, but it's open for discussion, we might want to take the trade-offs and additional implementation trouble.
https://crates.io/crates/sevenz-rust supports compression since version `0.2.0`.
@Aziks0 thanks for pointing this out, I labeled this issue as "good first issue" in case someone wants to take it.

Fix patch:
diff --git a/.gitignore b/.gitignore
index b5355c780..920e58de8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,3 +16,7 @@ artifacts/
 /benchmarks/input.*
 /benchmarks/*.md
 !/benchmarks/results.md
+
+# IDE-specific setting
+.vscode
+.idea
diff --git a/CHANGELOG.md b/CHANGELOG.md
index edfb9896c..b22b4c9d7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -21,6 +21,7 @@ Categories Used:
 ## [Unreleased](https://github.com/ouch-org/ouch/compare/0.4.2...HEAD)
 - Add support for listing and decompressing `.rar` archives
 - Fix mime type detection
+- Add support for 7z [\#555](https://github.com/ouch-org/ouch/pull/555) ([Flat](https://github.com/flat) & [MissileLab](https://github.com/MisileLab))
 
 ### Bug Fixes
 
diff --git a/Cargo.lock b/Cargo.lock
index dde3d3ccb..0f0ac61ed 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -10,18 +10,18 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 
 [[package]]
 name = "aho-corasick"
-version = "1.0.2"
+version = "1.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41"
+checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
 dependencies = [
  "memchr",
 ]
 
 [[package]]
 name = "anstream"
-version = "0.6.1"
+version = "0.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6cd65a4b849ace0b7f6daeebcc1a1d111282227ca745458c61dbf670e52a597"
+checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44"
 dependencies = [
  "anstyle",
  "anstyle-parse",
@@ -33,15 +33,15 @@ dependencies = [
 
 [[package]]
 name = "anstyle"
-version = "1.0.1"
+version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd"
+checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
 
 [[package]]
 name = "anstyle-parse"
-version = "0.2.1"
+version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
+checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140"
 dependencies = [
  "utf8parse",
 ]
@@ -57,9 +57,9 @@ dependencies = [
 
 [[package]]
 name = "anstyle-wincon"
-version = "3.0.0"
+version = "3.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0238ca56c96dfa37bdf7c373c8886dd591322500aceeeccdb2216fe06dc2f796"
+checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628"
 dependencies = [
  "anstyle",
  "windows-sys 0.48.0",
@@ -124,6 +124,15 @@ version = "2.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
 
+[[package]]
+name = "block-buffer"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
+dependencies = [
+ "generic-array",
+]
+
 [[package]]
 name = "bstr"
 version = "1.8.0"
@@ -131,27 +140,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "542f33a8835a0884b006a0c3df3dadd99c0c3f296ed26c2fdc8028e01ad6230c"
 dependencies = [
  "memchr",
- "regex-automata 0.4.1",
+ "regex-automata",
  "serde",
 ]
 
 [[package]]
 name = "bumpalo"
-version = "3.13.0"
+version = "3.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
+checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
 
 [[package]]
 name = "byteorder"
-version = "1.4.3"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
 
 [[package]]
 name = "bytes"
-version = "1.4.0"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
+checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
 
 [[package]]
 name = "bzip2"
@@ -201,6 +210,15 @@ version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
+[[package]]
+name = "chrono"
+version = "0.4.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
+dependencies = [
+ "num-traits",
+]
+
 [[package]]
 name = "clap"
 version = "4.4.8"
@@ -289,6 +307,30 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "cpufeatures"
+version = "0.2.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "crc"
+version = "3.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe"
+dependencies = [
+ "crc-catalog",
+]
+
+[[package]]
+name = "crc-catalog"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
+
 [[package]]
 name = "crc32fast"
 version = "1.3.2"
@@ -346,6 +388,15 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
 
+[[package]]
+name = "digest"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
+dependencies = [
+ "generic-array",
+]
+
 [[package]]
 name = "doc-comment"
 version = "0.3.3"
@@ -366,30 +417,19 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
 
 [[package]]
 name = "errno"
-version = "0.3.2"
+version = "0.3.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f"
+checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8"
 dependencies = [
- "errno-dragonfly",
  "libc",
  "windows-sys 0.48.0",
 ]
 
-[[package]]
-name = "errno-dragonfly"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
-dependencies = [
- "cc",
- "libc",
-]
-
 [[package]]
 name = "fastrand"
-version = "2.0.0"
+version = "2.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"
+checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
 
 [[package]]
 name = "filetime"
@@ -403,6 +443,17 @@ dependencies = [
  "windows-sys 0.48.0",
 ]
 
+[[package]]
+name = "filetime_creation"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3aea213d5ab4e6cd49f50c0688a4e20e5b75ff3bc07ff63f814778bd9b1dd42d"
+dependencies = [
+ "cfg-if",
+ "filetime",
+ "windows-sys 0.48.0",
+]
+
 [[package]]
 name = "flate2"
 version = "1.0.28"
@@ -444,21 +495,31 @@ dependencies = [
 
 [[package]]
 name = "futures-core"
-version = "0.3.28"
+version = "0.3.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
+checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c"
 
 [[package]]
 name = "futures-sink"
-version = "0.3.28"
+version = "0.3.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e"
+checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817"
+
+[[package]]
+name = "generic-array"
+version = "0.14.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
+dependencies = [
+ "typenum",
+ "version_check",
+]
 
 [[package]]
 name = "getrandom"
-version = "0.2.10"
+version = "0.2.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
+checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
 dependencies = [
  "cfg-if",
  "js-sys",
@@ -514,9 +575,9 @@ dependencies = [
 
 [[package]]
 name = "hermit-abi"
-version = "0.3.2"
+version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
+checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
 
 [[package]]
 name = "ignore"
@@ -568,27 +629,27 @@ dependencies = [
 
 [[package]]
 name = "itertools"
-version = "0.10.5"
+version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
+checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
 dependencies = [
  "either",
 ]
 
 [[package]]
 name = "jobserver"
-version = "0.1.26"
+version = "0.1.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2"
+checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d"
 dependencies = [
  "libc",
 ]
 
 [[package]]
 name = "js-sys"
-version = "0.3.64"
+version = "0.3.65"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
+checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8"
 dependencies = [
  "wasm-bindgen",
 ]
@@ -607,9 +668,9 @@ checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
 
 [[package]]
 name = "libm"
-version = "0.2.7"
+version = "0.2.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
+checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
 
 [[package]]
 name = "libz-sys"
@@ -631,15 +692,15 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.4.10"
+version = "0.4.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f"
+checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829"
 
 [[package]]
 name = "lock_api"
-version = "0.4.10"
+version = "0.4.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
+checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
 dependencies = [
  "autocfg",
  "scopeguard",
@@ -647,9 +708,9 @@ dependencies = [
 
 [[package]]
 name = "log"
-version = "0.4.19"
+version = "0.4.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
+checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
 
 [[package]]
 name = "lz4_flex"
@@ -660,6 +721,15 @@ dependencies = [
  "twox-hash",
 ]
 
+[[package]]
+name = "lzma-rust"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f798132166cc040cb70dbab4ccbb89643a6966a4ac33f0b312e76a8238673a5"
+dependencies = [
+ "byteorder",
+]
+
 [[package]]
 name = "lzma-sys"
 version = "0.1.20"
@@ -673,9 +743,9 @@ dependencies = [
 
 [[package]]
 name = "memchr"
-version = "2.6.1"
+version = "2.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f478948fd84d9f8e86967bf432640e46adfb5a4bd4f14ef7e864ab38220534ae"
+checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
 
 [[package]]
 name = "memoffset"
@@ -704,11 +774,21 @@ dependencies = [
  "getrandom",
 ]
 
+[[package]]
+name = "nt-time"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1d4f129ec1833164165b1711c30b4fa4a2b12784ffefa9fe877b016704b7165"
+dependencies = [
+ "chrono",
+ "time",
+]
+
 [[package]]
 name = "num-traits"
-version = "0.2.16"
+version = "0.2.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
+checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
 dependencies = [
  "autocfg",
  "libm",
@@ -720,7 +800,7 @@ version = "1.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
 dependencies = [
- "hermit-abi 0.3.2",
+ "hermit-abi 0.3.3",
  "libc",
 ]
 
@@ -730,6 +810,12 @@ version = "1.18.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
 
+[[package]]
+name = "opaque-debug"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
+
 [[package]]
 name = "ouch"
 version = "0.4.2"
@@ -741,7 +827,7 @@ dependencies = [
  "clap",
  "clap_complete",
  "clap_mangen",
- "filetime",
+ "filetime_creation",
  "flate2",
  "fs-err",
  "gzp",
@@ -758,6 +844,7 @@ dependencies = [
  "rand",
  "rayon",
  "same-file",
+ "sevenz-rust",
  "snap",
  "tar",
  "tempfile",
@@ -835,9 +922,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
 
 [[package]]
 name = "predicates"
-version = "3.0.3"
+version = "3.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09963355b9f467184c04017ced4a2ba2d75cbcb4e7462690d388233253d4b1a9"
+checksum = "6dfc28575c2e3f19cb3c73b93af36460ae898d426eba6fc15b9bd2a5220758a0"
 dependencies = [
  "anstyle",
  "difflib",
@@ -863,9 +950,9 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.66"
+version = "1.0.69"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
+checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
 dependencies = [
  "unicode-ident",
 ]
@@ -898,9 +985,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
 
 [[package]]
 name = "quote"
-version = "1.0.32"
+version = "1.0.33"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965"
+checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
 dependencies = [
  "proc-macro2",
 ]
@@ -984,33 +1071,27 @@ dependencies = [
 
 [[package]]
 name = "regex"
-version = "1.9.5"
+version = "1.10.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47"
+checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
 dependencies = [
  "aho-corasick",
  "memchr",
- "regex-automata 0.3.8",
- "regex-syntax 0.7.5",
+ "regex-automata",
+ "regex-syntax 0.8.2",
 ]
 
 [[package]]
 name = "regex-automata"
-version = "0.3.8"
+version = "0.4.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795"
+checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
 dependencies = [
  "aho-corasick",
  "memchr",
- "regex-syntax 0.7.5",
+ "regex-syntax 0.8.2",
 ]
 
-[[package]]
-name = "regex-automata"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "465c6fc0621e4abc4187a2bda0937bfd4f722c2730b29562e19689ea796c9a4b"
-
 [[package]]
 name = "regex-syntax"
 version = "0.7.5"
@@ -1031,9 +1112,9 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316"
 
 [[package]]
 name = "rustix"
-version = "0.38.21"
+version = "0.38.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3"
+checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e"
 dependencies = [
  "bitflags 2.4.1",
  "errno",
@@ -1071,15 +1152,59 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
 
 [[package]]
 name = "serde"
-version = "1.0.185"
+version = "1.0.193"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.193"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "sevenz-rust"
+version = "0.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be9b6f69f1dfd54c3b568ffa45c310d6973a5e5148fd40cf515acaf38cf5bc31"
+checksum = "33c7d45965e6557597a30e2d12e15d6a5f438bb7cbc11d5dbe89762541c0cd42"
+dependencies = [
+ "bit-set",
+ "byteorder",
+ "crc",
+ "filetime_creation",
+ "js-sys",
+ "lzma-rust",
+ "nt-time",
+ "sha2",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "sha2"
+version = "0.9.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
+dependencies = [
+ "block-buffer",
+ "cfg-if",
+ "cpufeatures",
+ "digest",
+ "opaque-debug",
+]
 
 [[package]]
 name = "similar"
-version = "2.2.1"
+version = "2.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf"
+checksum = "2aeaf503862c419d66959f5d7ca015337d864e9c49485d771b732e2a20453597"
 
 [[package]]
 name = "snap"
@@ -1133,9 +1258,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.28"
+version = "2.0.39"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567"
+checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1186,18 +1311,18 @@ dependencies = [
 
 [[package]]
 name = "thiserror"
-version = "1.0.44"
+version = "1.0.50"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90"
+checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.44"
+version = "1.0.50"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96"
+checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1224,6 +1349,7 @@ dependencies = [
  "powerfmt",
  "serde",
  "time-core",
+ "time-macros",
 ]
 
 [[package]]
@@ -1232,6 +1358,15 @@ version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
 
+[[package]]
+name = "time-macros"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20"
+dependencies = [
+ "time-core",
+]
+
 [[package]]
 name = "twox-hash"
 version = "1.6.3"
@@ -1242,6 +1377,12 @@ dependencies = [
  "static_assertions",
 ]
 
+[[package]]
+name = "typenum"
+version = "1.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
+
 [[package]]
 name = "unarray"
 version = "0.1.4"
@@ -1250,9 +1391,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94"
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.11"
+version = "1.0.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
 
 [[package]]
 name = "unrar"
@@ -1285,9 +1426,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
 
 [[package]]
 name = "uuid"
-version = "1.4.1"
+version = "1.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d"
+checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560"
 
 [[package]]
 name = "vcpkg"
@@ -1295,6 +1436,12 @@ version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
 
+[[package]]
+name = "version_check"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+
 [[package]]
 name = "wait-timeout"
 version = "0.2.0"
@@ -1306,9 +1453,9 @@ dependencies = [
 
 [[package]]
 name = "walkdir"
-version = "2.3.3"
+version = "2.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698"
+checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
 dependencies = [
  "same-file",
  "winapi-util",
@@ -1322,9 +1469,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.87"
+version = "0.2.88"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
+checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce"
 dependencies = [
  "cfg-if",
  "wasm-bindgen-macro",
@@ -1332,9 +1479,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.87"
+version = "0.2.88"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
+checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217"
 dependencies = [
  "bumpalo",
  "log",
@@ -1347,9 +1494,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.87"
+version = "0.2.88"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
+checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -1357,9 +1504,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.87"
+version = "0.2.88"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
+checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1370,9 +1517,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.87"
+version = "0.2.88"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
+checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b"
 
 [[package]]
 name = "widestring"
@@ -1398,9 +1545,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
 
 [[package]]
 name = "winapi-util"
-version = "0.1.5"
+version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
 dependencies = [
  "winapi",
 ]
@@ -1426,7 +1573,7 @@ version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
 dependencies = [
- "windows-targets 0.48.1",
+ "windows-targets 0.48.5",
 ]
 
 [[package]]
@@ -1446,17 +1593,17 @@ dependencies = [
 
 [[package]]
 name = "windows-targets"
-version = "0.48.1"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
 dependencies = [
- "windows_aarch64_gnullvm 0.48.0",
- "windows_aarch64_msvc 0.48.0",
- "windows_i686_gnu 0.48.0",
- "windows_i686_msvc 0.48.0",
- "windows_x86_64_gnu 0.48.0",
- "windows_x86_64_gnullvm 0.48.0",
- "windows_x86_64_msvc 0.48.0",
+ "windows_aarch64_gnullvm 0.48.5",
+ "windows_aarch64_msvc 0.48.5",
+ "windows_i686_gnu 0.48.5",
+ "windows_i686_msvc 0.48.5",
+ "windows_x86_64_gnu 0.48.5",
+ "windows_x86_64_gnullvm 0.48.5",
+ "windows_x86_64_msvc 0.48.5",
 ]
 
 [[package]]
@@ -1467,9 +1614,9 @@ checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
 
 [[package]]
 name = "windows_aarch64_msvc"
@@ -1479,9 +1626,9 @@ checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
 
 [[package]]
 name = "windows_i686_gnu"
@@ -1491,9 +1638,9 @@ checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
 
 [[package]]
 name = "windows_i686_msvc"
@@ -1503,9 +1650,9 @@ checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
 
 [[package]]
 name = "windows_x86_64_gnu"
@@ -1515,9 +1662,9 @@ checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
@@ -1527,9 +1674,9 @@ checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
 
 [[package]]
 name = "windows_x86_64_msvc"
@@ -1539,9 +1686,9 @@ checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
 
 [[package]]
 name = "xattr"
@@ -1603,11 +1750,10 @@ dependencies = [
 
 [[package]]
 name = "zstd-sys"
-version = "2.0.8+zstd.1.5.5"
+version = "2.0.9+zstd.1.5.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c"
+checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656"
 dependencies = [
  "cc",
- "libc",
  "pkg-config",
 ]
diff --git a/Cargo.toml b/Cargo.toml
index 415a602f7..4c195b342 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -15,7 +15,7 @@ atty = "0.2.14"
 bstr = { version = "1.8.0", default-features = false, features = ["std"] }
 bzip2 = "0.4.4"
 clap = { version = "4.4.8", features = ["derive", "env"] }
-filetime = "0.2.22"
+filetime_creation = "0.1"
 flate2 = { version = "1.0.28", default-features = false }
 fs-err = "2.11.0"
 gzp = { version = "0.11.3", default-features = false, features = ["snappy_default"] }
@@ -26,6 +26,7 @@ lz4_flex = "0.11.1"
 once_cell = "1.18.0"
 rayon = "1.8.0"
 same-file = "1.0.6"
+sevenz-rust = {version = "0.5.3", features = ["compress"]}
 snap = "1.1.0"
 tar = "0.4.40"
 tempfile = "3.8.1"
diff --git a/src/archive/mod.rs b/src/archive/mod.rs
index 428f3cb04..077d16b4a 100644
--- a/src/archive/mod.rs
+++ b/src/archive/mod.rs
@@ -1,5 +1,6 @@
 //! Archive compression algorithms
 
 pub mod rar;
+pub mod sevenz;
 pub mod tar;
 pub mod zip;
diff --git a/src/archive/sevenz.rs b/src/archive/sevenz.rs
new file mode 100644
index 000000000..0847f4ca5
--- /dev/null
+++ b/src/archive/sevenz.rs
@@ -0,0 +1,155 @@
+//! SevenZip archive format compress function
+
+use std::{
+    env, io,
+    io::{Read, Seek, Write},
+    path::{Path, PathBuf},
+};
+
+use fs_err as fs;
+use same_file::Handle;
+
+use crate::{
+    error::FinalError,
+    info,
+    utils::{self, cd_into_same_dir_as, Bytes, EscapedPathDisplay, FileVisibilityPolicy},
+    warning,
+};
+
+pub fn compress_sevenz<W>(
+    files: &[PathBuf],
+    output_path: &Path,
+    writer: W,
+    file_visibility_policy: FileVisibilityPolicy,
+    quiet: bool,
+) -> crate::Result<W>
+where
+    W: Write + Seek,
+{
+    let mut writer = sevenz_rust::SevenZWriter::new(writer)?;
+    let output_handle = Handle::from_path(output_path);
+
+    for filename in files {
+        let previous_location = cd_into_same_dir_as(filename)?;
+
+        // Unwrap safety:
+        //   paths should be canonicalized by now, and the root directory rejected.
+        let filename = filename.file_name().unwrap();
+
+        for entry in file_visibility_policy.build_walker(filename) {
+            let entry = entry?;
+            let path = entry.path();
+
+            // If the output_path is the same as the input file, warn the user and skip the input (in order to avoid compression recursion)
+            if let Ok(handle) = &output_handle {
+                if matches!(Handle::from_path(path), Ok(x) if &x == handle) {
+                    warning!(
+                        "The output file and the input file are the same: `{}`, skipping...",
+                        output_path.display()
+                    );
+                    continue;
+                }
+            }
+
+            // This is printed for every file in `input_filenames` and has
+            // little importance for most users, but would generate lots of
+            // spoken text for users using screen readers, braille displays
+            // and so on
+            if !quiet {
+                info!(inaccessible, "Compressing '{}'.", EscapedPathDisplay::new(path));
+            }
+
+            let metadata = match path.metadata() {
+                Ok(metadata) => metadata,
+                Err(e) => {
+                    if e.kind() == std::io::ErrorKind::NotFound && utils::is_symlink(path) {
+                        // This path is for a broken symlink
+                        // We just ignore it
+                        continue;
+                    }
+                    return Err(e.into());
+                }
+            };
+
+            let entry_name = path.to_str().ok_or_else(|| {
+                FinalError::with_title("7z requires that all entry names are valid UTF-8")
+                    .detail(format!("File at '{path:?}' has a non-UTF-8 name"))
+            })?;
+
+            let entry = sevenz_rust::SevenZArchiveEntry::from_path(path, entry_name.to_owned());
+            let entry_data = if metadata.is_dir() {
+                None
+            } else {
+                Some(fs::File::open(path)?)
+            };
+
+            writer.push_archive_entry::<fs::File>(entry, entry_data)?;
+        }
+
+        env::set_current_dir(previous_location)?;
+    }
+
+    let bytes = writer.finish()?;
+    Ok(bytes)
+}
+
+pub fn decompress_sevenz<R>(reader: R, output_path: &Path, quiet: bool) -> crate::Result<usize>
+where
+    R: Read + Seek,
+{
+    let mut count: usize = 0;
+    sevenz_rust::decompress_with_extract_fn(reader, output_path, |entry, reader, path| {
+        count += 1;
+        // Manually handle writing all files from 7z archive, due to library exluding empty files
+        use std::io::BufWriter;
+
+        use filetime_creation as ft;
+
+        let file_path = output_path.join(entry.name());
+
+        if entry.is_directory() {
+            if !quiet {
+                info!(
+                    inaccessible,
+                    "File {} extracted to \"{}\"",
+                    entry.name(),
+                    file_path.display()
+                );
+            }
+            if !path.exists() {
+                fs::create_dir_all(path)?;
+            }
+        } else {
+            if !quiet {
+                info!(
+                    inaccessible,
+                    "{:?} extracted. ({})",
+                    file_path.display(),
+                    Bytes::new(entry.size()),
+                );
+            }
+
+            if let Some(parent) = path.parent() {
+                if !parent.exists() {
+                    fs::create_dir_all(parent)?;
+                }
+            }
+
+            let file = fs::File::create(path)?;
+            let mut writer = BufWriter::new(file);
+            io::copy(reader, &mut writer)?;
+
+            ft::set_file_handle_times(
+                writer.get_ref().file(),
+                Some(ft::FileTime::from_system_time(entry.access_date().into())),
+                Some(ft::FileTime::from_system_time(entry.last_modified_date().into())),
+                Some(ft::FileTime::from_system_time(entry.creation_date().into())),
+            )
+            .unwrap_or_default();
+        }
+
+        Ok(true)
+    })?;
+
+    Ok(count)
+}
diff --git a/src/archive/tar.rs b/src/archive/tar.rs
index d37628819..822212283 100644
--- a/src/archive/tar.rs
+++ b/src/archive/tar.rs
@@ -96,7 +96,8 @@ where
     for filename in input_filenames {
         let previous_location = utils::cd_into_same_dir_as(filename)?;
 
-        // Safe unwrap, input shall be treated before
+        // Unwrap safety:
+        //   paths should be canonicalized by now, and the root directory rejected.
         let filename = filename.file_name().unwrap();
 
         for entry in file_visibility_policy.build_walker(filename) {
@@ -104,7 +105,7 @@ where
             let path = entry.path();
 
             // If the output_path is the same as the input file, warn the user and skip the input (in order to avoid compression recursion)
-            if let Ok(ref handle) = output_handle {
+            if let Ok(handle) = &output_handle {
                 if matches!(Handle::from_path(path), Ok(x) if &x == handle) {
                     warning!(
                         "The output file and the input file are the same: `{}`, skipping...",
diff --git a/src/archive/zip.rs b/src/archive/zip.rs
index 60cc440db..e9bde15d6 100644
--- a/src/archive/zip.rs
+++ b/src/archive/zip.rs
@@ -10,7 +10,7 @@ use std::{
     thread,
 };
 
-use filetime::{set_file_mtime, FileTime};
+use filetime_creation::{set_file_mtime, FileTime};
 use fs_err as fs;
 use same_file::Handle;
 use time::OffsetDateTime;
@@ -167,7 +167,8 @@ where
     for filename in input_filenames {
         let previous_location = cd_into_same_dir_as(filename)?;
 
-        // Safe unwrap, input shall be treated before
+        // Unwrap safety:
+        //   paths should be canonicalized by now, and the root directory rejected.
         let filename = filename.file_name().unwrap();
 
         for entry in file_visibility_policy.build_walker(filename) {
@@ -175,7 +176,7 @@ where
             let path = entry.path();
 
             // If the output_path is the same as the input file, warn the user and skip the input (in order to avoid compression recursion)
-            if let Ok(ref handle) = output_handle {
+            if let Ok(handle) = &output_handle {
                 if matches!(Handle::from_path(path), Ok(x) if &x == handle) {
                     warning!(
                         "The output file and the input file are the same: `{}`, skipping...",
@@ -208,8 +209,13 @@ where
             #[cfg(unix)]
             let options = options.unix_permissions(metadata.permissions().mode());
 
+            let entry_name = path.to_str().ok_or_else(|| {
+                FinalError::with_title("Zip requires that all directories names are valid UTF-8")
+                    .detail(format!("File at '{path:?}' has a non-UTF-8 name"))
+            })?;
+
             if metadata.is_dir() {
-                writer.add_directory(path.to_str().unwrap().to_owned(), options)?;
+                writer.add_directory(entry_name, options)?;
             } else {
                 #[cfg(not(unix))]
                 let options = if is_executable::is_executable(path) {
@@ -219,10 +225,11 @@ where
                 };
 
                 let mut file = fs::File::open(path)?;
-                writer.start_file(
-                    path.to_str().unwrap(),
-                    options.last_modified_time(get_last_modified_time(&file)),
-                )?;
+
+                // Updated last modified time
+                let last_modified_time = options.last_modified_time(get_last_modified_time(&file));
+
+                writer.start_file(entry_name, last_modified_time)?;
                 io::copy(&mut file, &mut writer)?;
             }
         }
diff --git a/src/commands/compress.rs b/src/commands/compress.rs
index 72e92c490..5150fff9c 100644
--- a/src/commands/compress.rs
+++ b/src/commands/compress.rs
@@ -5,6 +5,7 @@ use std::{
 
 use fs_err as fs;
 
+use super::warn_user_about_loading_sevenz_in_memory;
 use crate::{
     archive,
     commands::warn_user_about_loading_zip_in_memory,
@@ -79,7 +80,7 @@ pub fn compress_files(
                 //     is `clamp`ed and therefore guaranteed to be valid
                 Box::new(zstd_encoder.unwrap().auto_finish())
             }
-            Tar | Zip | Rar => unreachable!(),
+            Tar | Zip | Rar | SevenZip => unreachable!(),
         };
         Ok(encoder)
     };
@@ -126,6 +127,20 @@ pub fn compress_files(
             archive::rar::no_compression_notice();
             return Ok(false);
         }
+        SevenZip => {
+            if !formats.is_empty() {
+                warn_user_about_loading_sevenz_in_memory();
+
+                if !user_wants_to_continue(output_path, question_policy, QuestionAction::Compression)? {
+                    return Ok(false);
+                }
+            }
+
+            let mut vec_buffer = Cursor::new(vec![]);
+            archive::sevenz::compress_sevenz(&files, output_path, &mut vec_buffer, file_visibility_policy, quiet)?;
+            vec_buffer.rewind()?;
+            io::copy(&mut vec_buffer, &mut writer)?;
+        }
     }
 
     Ok(true)
diff --git a/src/commands/decompress.rs b/src/commands/decompress.rs
index 9ae0adeb0..c717dbcfa 100644
--- a/src/commands/decompress.rs
+++ b/src/commands/decompress.rs
@@ -7,7 +7,7 @@ use std::{
 use fs_err as fs;
 
 use crate::{
-    commands::warn_user_about_loading_zip_in_memory,
+    commands::{warn_user_about_loading_sevenz_in_memory, warn_user_about_loading_zip_in_memory},
     extension::{
         split_first_compression_format,
         CompressionFormat::{self, *},
@@ -86,7 +86,7 @@ pub fn decompress_file(
             Lzma => Box::new(xz2::read::XzDecoder::new(decoder)),
             Snappy => Box::new(snap::read::FrameDecoder::new(decoder)),
             Zstd => Box::new(zstd::stream::Decoder::new(decoder)?),
-            Tar | Zip | Rar => unreachable!(),
+            Tar | Zip | Rar | SevenZip => unreachable!(),
         };
         Ok(decoder)
     };
@@ -164,6 +164,29 @@ pub fn decompress_file(
                 return Ok(());
             }
         }
+        SevenZip => {
+            if formats.len() > 1 {
+                warn_user_about_loading_sevenz_in_memory();
+
+                if !user_wants_to_continue(input_file_path, question_policy, QuestionAction::Decompression)? {
+                    return Ok(());
+                }
+            }
+
+            let mut vec = vec![];
+            io::copy(&mut reader, &mut vec)?;
+
+            if let ControlFlow::Continue(files) = smart_unpack(
+                |output_dir| crate::archive::sevenz::decompress_sevenz(io::Cursor::new(vec), output_dir, quiet),
+                output_dir,
+                &output_file_path,
+                question_policy,
+            )? {
+                files
+            } else {
+                return Ok(());
+            }
+        }
     };
 
     // this is only printed once, so it doesn't result in much text. On the other hand,
diff --git a/src/commands/list.rs b/src/commands/list.rs
index e33d9997e..f89830fe6 100644
--- a/src/commands/list.rs
+++ b/src/commands/list.rs
@@ -52,7 +52,7 @@ pub fn list_archive_contents(
                 Lzma => Box::new(xz2::read::XzDecoder::new(decoder)),
                 Snappy => Box::new(snap::read::FrameDecoder::new(decoder)),
                 Zstd => Box::new(zstd::stream::Decoder::new(decoder)?),
-                Tar | Zip | Rar => unreachable!(),
+                Tar | Zip | Rar | SevenZip => unreachable!(),
             };
             Ok(decoder)
         };
@@ -87,6 +87,25 @@ pub fn list_archive_contents(
                 Box::new(crate::archive::rar::list_archive(archive_path))
             }
         }
+        SevenZip => {
+            if formats.len() > 1 {
+                warn_user_about_loading_zip_in_memory();
+                if !user_wants_to_continue(archive_path, question_policy, QuestionAction::Decompression)? {
+                    return Ok(());
+                }
+            }
+
+            let mut files = Vec::new();
+
+            sevenz_rust::decompress_file_with_extract_fn(archive_path, ".", |entry, _, _| {
+                files.push(Ok(FileInArchive {
+                    path: entry.name().into(),
+                    is_dir: entry.is_directory(),
+                }));
+                Ok(true)
+            })?;
+            Box::new(files.into_iter())
+        }
         Gzip | Bzip | Lz4 | Lzma | Snappy | Zstd => {
             panic!("Not an archive! This should never happen, if it does, something is wrong with `CompressionFormat::is_archive()`. Please report this error!");
         }
diff --git a/src/commands/mod.rs b/src/commands/mod.rs
index e5be2330a..b9763d1fc 100644
--- a/src/commands/mod.rs
+++ b/src/commands/mod.rs
@@ -31,6 +31,16 @@ fn warn_user_about_loading_zip_in_memory() {
     warning!("{}", ZIP_IN_MEMORY_LIMITATION_WARNING);
 }
 
+/// Warn the user that (de)compressing this .7z archive might freeze their system.
+fn warn_user_about_loading_sevenz_in_memory() {
+    const SEVENZ_IN_MEMORY_LIMITATION_WARNING: &str = "\n\
+        \tThe format '.7z' is limited and cannot be (de)compressed using encoding streams.\n\
+        \tWhen using '.7z' with other formats, (de)compression must be done in-memory\n\
+        \tCareful, you might run out of RAM if the archive is too large!";
+
+    warning!("{}", SEVENZ_IN_MEMORY_LIMITATION_WARNING);
+}
+
 /// This function checks what command needs to be run and performs A LOT of ahead-of-time checks
 /// to assume everything is OK.
 ///
diff --git a/src/error.rs b/src/error.rs
index 896f383ac..1b48623de 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -34,6 +34,8 @@ pub enum Error {
     Custom { reason: FinalError },
     /// Invalid format passed to `--format`
     InvalidFormat { reason: String },
+    /// From sevenz_rust::Error
+    SevenzipError(sevenz_rust::Error),
 }
 
 /// Alias to std's Result with ouch's Error
@@ -139,6 +141,7 @@ impl fmt::Display for Error {
             Error::UnsupportedZipArchive(reason) => FinalError::with_title("Unsupported zip archive").detail(*reason),
             Error::InvalidFormat { reason } => FinalError::with_title("Invalid archive format").detail(reason.clone()),
             Error::Custom { reason } => reason.clone(),
+            Error::SevenzipError(reason) => FinalError::with_title("7z error").detail(reason.to_string()),
         };
 
         write!(f, "{err}")
@@ -186,6 +189,12 @@ impl From<unrar::error::UnrarError> for Error {
     }
 }
 
+impl From<sevenz_rust::Error> for Error {
+    fn from(err: sevenz_rust::Error) -> Self {
+        Self::SevenzipError(err)
+    }
+}
+
 impl From<ignore::Error> for Error {
     fn from(err: ignore::Error) -> Self {
         Self::WalkdirError {
diff --git a/src/extension.rs b/src/extension.rs
index 85451cb3b..b4029a825 100644
--- a/src/extension.rs
+++ b/src/extension.rs
@@ -7,7 +7,9 @@ use bstr::ByteSlice;
 use self::CompressionFormat::*;
 use crate::{error::Error, warning};
 
-pub const SUPPORTED_EXTENSIONS: &[&str] = &["tar", "zip", "bz", "bz2", "gz", "lz4", "xz", "lzma", "sz", "zst", "rar"];
+pub const SUPPORTED_EXTENSIONS: &[&str] = &[
+    "tar", "zip", "bz", "bz2", "gz", "lz4", "xz", "lzma", "sz", "zst", "rar", "7z",
+];
 pub const SUPPORTED_ALIASES: &[&str] = &["tgz", "tbz", "tlz4", "txz", "tzlma", "tsz", "tzst"];
 pub const PRETTY_SUPPORTED_EXTENSIONS: &str = "tar, zip, bz, bz2, gz, lz4, xz, lzma, sz, zst, rar";
 pub const PRETTY_SUPPORTED_ALIASES: &str = "tgz, tbz, tlz4, txz, tzlma, tsz, tzst";
@@ -74,6 +76,8 @@ pub enum CompressionFormat {
     Zip,
     /// .rar
     Rar,
+    /// .7z
+    SevenZip,
 }
 
 impl CompressionFormat {
@@ -81,7 +85,7 @@ impl CompressionFormat {
     fn is_archive_format(&self) -> bool {
         // Keep this match like that without a wildcard `_` so we don't forget to update it
         match self {
-            Tar | Zip | Rar => true,
+            Tar | Zip | Rar | SevenZip => true,
             Gzip => false,
             Bzip => false,
             Lz4 => false,
@@ -110,6 +114,7 @@ fn to_extension(ext: &[u8]) -> Option<Extension> {
             b"sz" => &[Snappy],
             b"zst" => &[Zstd],
             b"rar" => &[Rar],
+            b"7z" => &[SevenZip],
             _ => return None,
         },
         ext.to_str_lossy(),
diff --git a/src/utils/fs.rs b/src/utils/fs.rs
index 08f6d1bac..dbd422e0e 100644
--- a/src/utils/fs.rs
+++ b/src/utils/fs.rs
@@ -91,6 +91,9 @@ pub fn try_infer_extension(path: &Path) -> Option<Extension> {
             && buf.starts_with(&[0x52, 0x61, 0x72, 0x21, 0x1A, 0x07])
             && (buf[6] == 0x00 || (buf.len() >= 8 && buf[6..=7] == [0x01, 0x00]))
     }
+    fn is_sevenz(buf: &[u8]) -> bool {
+        buf.starts_with(&[0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C])
+    }
 
     let buf = {
         let mut buf = [0; 270];
@@ -124,6 +127,8 @@ pub fn try_infer_extension(path: &Path) -> Option<Extension> {
         Some(Extension::new(&[Zstd], "zst"))
     } else if is_rar(&buf) {
         Some(Extension::new(&[Rar], "rar"))
+    } else if is_sevenz(&buf) {
+        Some(Extension::new(&[SevenZip], "7z"))
     } else {
         None
     }


Test patch:
diff --git a/tests/integration.rs b/tests/integration.rs
index b67b3ee84..f88e56827 100644
--- a/tests/integration.rs
+++ b/tests/integration.rs
@@ -19,6 +19,8 @@ use crate::utils::{assert_same_directory, write_random_content};
 #[derive(Arbitrary, Debug, Display)]
 #[display(style = "lowercase")]
 enum DirectoryExtension {
+    #[display("7z")]
+    SevenZ,
     Tar,
     Tbz,
     Tbz2,
diff --git a/tests/mime.rs b/tests/mime.rs
index 1f340d078..bf5217984 100644
--- a/tests/mime.rs
+++ b/tests/mime.rs
@@ -17,11 +17,12 @@ fn sanity_check_through_mime() {
     write_random_content(test_file, &mut SmallRng::from_entropy());
 
     let formats = [
-        "tar", "zip", "tar.gz", "tgz", "tbz", "tbz2", "txz", "tlzma", "tzst", "tar.bz", "tar.bz2", "tar.lzma",
+        "7z", "tar", "zip", "tar.gz", "tgz", "tbz", "tbz2", "txz", "tlzma", "tzst", "tar.bz", "tar.bz2", "tar.lzma",
         "tar.xz", "tar.zst",
     ];
 
     let expected_mimes = [
+        "application/x-7z-compressed",
         "application/x-tar",
         "application/zip",
         "application/gzip",