diff --git a/src/bin/bat/app.rs b/src/bin/bat/app.rs
index ae889453..542e5d99 100644
--- a/src/bin/bat/app.rs
+++ b/src/bin/bat/app.rs
@@ -136,6 +136,13 @@ impl App {
             }
         });
 
+        match self.matches.values_of("file-name") {
+            Some(filenames) if filenames.len() != files.len() => {
+                return Err(format!("{} {}", filenames.len(), files.len()).into());
+            }
+            _ => {}
+        }
+
         Ok(Config {
             true_color: is_truecolor_terminal(),
             language: self.matches.value_of("language").or_else(|| {
@@ -222,6 +229,10 @@ impl App {
                 .map(LineRanges::from)
                 .map(|lr| HighlightedLineRanges(lr))
                 .unwrap_or_default(),
+            filenames: self
+                .matches
+                .values_of("file-name")
+                .map(|values| values.collect()),
         })
     }
 
diff --git a/src/bin/bat/clap_app.rs b/src/bin/bat/clap_app.rs
index 2f7c0a5a..c2505ca9 100644
--- a/src/bin/bat/clap_app.rs
+++ b/src/bin/bat/clap_app.rs
@@ -93,6 +93,18 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
                      '--highlight-line 40:' highlights lines 40 to the end of the file"
                 ),
         )
+        .arg(
+            Arg::with_name("file-name")
+                .long("file-name")
+                .takes_value(true)
+                .number_of_values(1)
+                .multiple(true)
+                .value_name("name")
+                .help("Specify the name to display for a file.")
+                .long_help("Specify the name to display for a file. Useful when piping \
+                            data to bat from STDIN when bat does not otherwise know \
+                            the filename."),
+        )
         .arg(
             Arg::with_name("tabs")
                 .long("tabs")
diff --git a/src/config.rs b/src/config.rs
index 19e91484..6a0c2530 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -70,6 +70,9 @@ pub struct Config<'a> {
 
     /// Ranges of lines which should be highlighted with a special background color
     pub highlighted_lines: HighlightedLineRanges,
+
+    /// Names of files to display when printing
+    pub filenames: Option<Vec<&'a str>>,
 }
 
 #[test]
diff --git a/src/controller.rs b/src/controller.rs
index ee1a1be3..90e465bd 100644
--- a/src/controller.rs
+++ b/src/controller.rs
@@ -45,7 +45,12 @@ impl<'b> Controller<'b> {
 
         let stdin = io::stdin();
 
-        for input_file in &self.config.files {
+        let filenames: Box<dyn Iterator<Item = _>> = match self.config.filenames {
+            Some(ref filenames) => Box::new(filenames.into_iter().map(|name| Some(*name))),
+            None => Box::new(std::iter::repeat(None)),
+        };
+
+        for (input_file, file_name) in self.config.files.iter().zip(filenames) {
             match input_file.get_reader(&stdin) {
                 Err(error) => {
                     handle_error(&error);
@@ -54,7 +59,7 @@ impl<'b> Controller<'b> {
                 Ok(mut reader) => {
                     let result = if self.config.loop_through {
                         let mut printer = SimplePrinter::new();
-                        self.print_file(reader, &mut printer, writer, *input_file)
+                        self.print_file(reader, &mut printer, writer, *input_file, file_name)
                     } else {
                         let mut printer = InteractivePrinter::new(
                             &self.config,
@@ -62,7 +67,7 @@ impl<'b> Controller<'b> {
                             *input_file,
                             &mut reader,
                         );
-                        self.print_file(reader, &mut printer, writer, *input_file)
+                        self.print_file(reader, &mut printer, writer, *input_file, file_name)
                     };
 
                     if let Err(error) = result {
@@ -82,9 +87,10 @@ impl<'b> Controller<'b> {
         printer: &mut P,
         writer: &mut dyn Write,
         input_file: InputFile<'a>,
+        file_name: Option<&str>,
     ) -> Result<()> {
         if !reader.first_line.is_empty() || self.config.style_components.header() {
-            printer.print_header(writer, input_file)?;
+            printer.print_header(writer, input_file, file_name)?;
         }
 
         if !reader.first_line.is_empty() {
diff --git a/src/printer.rs b/src/printer.rs
index 629b11da..3924cd62 100644
--- a/src/printer.rs
+++ b/src/printer.rs
@@ -34,7 +34,12 @@ use crate::terminal::{as_terminal_escaped, to_ansi_color};
 use crate::wrap::OutputWrap;
 
 pub trait Printer {
-    fn print_header(&mut self, handle: &mut dyn Write, file: InputFile) -> Result<()>;
+    fn print_header(
+        &mut self,
+        handle: &mut dyn Write,
+        file: InputFile,
+        file_name: Option<&str>,
+    ) -> Result<()>;
     fn print_footer(&mut self, handle: &mut dyn Write) -> Result<()>;
 
     fn print_snip(&mut self, handle: &mut dyn Write) -> Result<()>;
@@ -57,7 +62,12 @@ impl SimplePrinter {
 }
 
 impl Printer for SimplePrinter {
-    fn print_header(&mut self, _handle: &mut dyn Write, _file: InputFile) -> Result<()> {
+    fn print_header(
+        &mut self,
+        _handle: &mut dyn Write,
+        _file: InputFile,
+        _file_name: Option<&str>,
+    ) -> Result<()> {
         Ok(())
     }
 
@@ -224,14 +234,20 @@ impl<'a> InteractivePrinter<'a> {
 }
 
 impl<'a> Printer for InteractivePrinter<'a> {
-    fn print_header(&mut self, handle: &mut dyn Write, file: InputFile) -> Result<()> {
+    fn print_header(
+        &mut self,
+        handle: &mut dyn Write,
+        file: InputFile,
+        file_name: Option<&str>,
+    ) -> Result<()> {
         if !self.config.style_components.header() {
             if Some(ContentType::BINARY) == self.content_type && !self.config.show_nonprintable {
                 let input = match file {
-                    InputFile::Ordinary(filename) => {
-                        format!("file '{}'", filename.to_string_lossy())
-                    }
-                    _ => "STDIN".into(),
+                    InputFile::Ordinary(filename) => format!(
+                        "file '{}'",
+                        file_name.unwrap_or(&filename.to_string_lossy())
+                    ),
+                    _ => file_name.unwrap_or("STDIN").to_owned(),
                 };
 
                 writeln!(
@@ -266,8 +282,11 @@ impl<'a> Printer for InteractivePrinter<'a> {
         }
 
         let (prefix, name) = match file {
-            InputFile::Ordinary(filename) => ("File: ", filename.to_string_lossy()),
-            _ => ("", Cow::from("STDIN")),
+            InputFile::Ordinary(filename) => (
+                "File: ",
+                Cow::from(file_name.unwrap_or(&filename.to_string_lossy()).to_owned()),
+            ),
+            _ => ("File: ", Cow::from(file_name.unwrap_or("STDIN").to_owned())),
         };
 
         let mode = match self.content_type {
diff --git a/tests/examples/test.binary b/tests/examples/test.binary
new file mode 100644
index 00000000..593f4708
Binary files /dev/null and b/tests/examples/test.binary differ
diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs
index 0d5f4a3c..7750f6cd 100644
--- a/tests/integration_tests.rs
+++ b/tests/integration_tests.rs
@@ -541,3 +541,89 @@ fn empty_file_leads_to_empty_output_with_grid_enabled() {
         .success()
         .stdout("");
 }
+
+#[test]
+fn filename_basic() {
+    bat()
+        .arg("test.txt")
+        .arg("--decorations=always")
+        .arg("--style=header")
+        .arg("-r=0:0")
+        .arg("--file-name=foo")
+        .assert()
+        .success()
+        .stdout("File: foo\n")
+        .stderr("");
+}
+
+#[test]
+fn filename_binary() {
+    bat()
+        .arg("test.binary")
+        .arg("--decorations=always")
+        .arg("--style=header")
+        .arg("-r=0:0")
+        .arg("--file-name=foo")
+        .assert()
+        .success()
+        .stdout("File: foo   <BINARY>\n")
+        .stderr("");
+}
+
+#[test]
+fn filename_stdin() {
+    bat()
+        .arg("--decorations=always")
+        .arg("--style=header")
+        .arg("-r=0:0")
+        .arg("-")
+        .write_stdin("stdin\n")
+        .arg("--file-name=foo")
+        .assert()
+        .success()
+        .stdout("File: foo\n")
+        .stderr("");
+}
+
+#[test]
+fn filename_stdin_binary() {
+    let vec = vec![0; 1];
+    bat_with_config()
+        .arg("--decorations=always")
+        .arg("--style=header")
+        .write_stdin(vec)
+        .arg("--file-name=foo")
+        .assert()
+        .success()
+        .stdout("File: foo   <BINARY>\n")
+        .stderr("");
+}
+
+#[test]
+fn filename_multiple_ok() {
+    bat()
+        .arg("--decorations=always")
+        .arg("--style=header")
+        .arg("-r=0:0")
+        .arg("test.txt")
+        .arg("--file-name=foo")
+        .arg("single-line.txt")
+        .arg("--file-name=bar")
+        .assert()
+        .success()
+        .stdout("File: foo\nFile: bar\n")
+        .stderr("");
+}
+
+#[test]
+fn filename_multiple_err() {
+    bat()
+        .arg("--decorations=always")
+        .arg("--style=header")
+        .arg("-r=0:0")
+        .arg("test.txt")
+        .arg("--file-name=foo")
+        .arg("single-line.txt")
+        .assert()
+        .failure();
+}