<p>Take your <code>BamFile(fake_bam)</code> and pass it through <code>open()</code>. That will return a value if <code>fake_bam</code> is a real BAM (or CRAM or maybe SAM) file and through an error otherwise. You can then wrap all of that in a <code>trycatch()</code>:</p>

<pre><code>trycatch(open(BamFile(fake_bam)), do something, do something else)
</code></pre>

<p>Alternatively, ditch the <code>trycatch()</code> and let <code>open()</code> return the error if an invalid file in entered.</p>

CC BY-SA 4.0
2018-05-02T05:33:28.687Z
2018-05-02T05:33:28.687Z
Devon Ryan
<p>Just expanding upon the answers by @DevonRyan and @KonradRudolph, here's one way to put this in an R package:</p>

<p>Either using <code>open(BamFile()</code> from Devon's answer, which needs <code>Rsamtools</code>:</p>

<pre><code>my_func = function(my_bam){

    out = tryCatch(open(Rsamtools::BamFile(my_bam)), error = function(e) e)
    if (inherits(out, "error")){
        stop("Input a valid BAM file.")
    }

    ## do awesome stuff with BAM
}
</code></pre>

<p>Or from Konrad's answer</p>

<pre><code>my_func = function(my_bam){

    magic = readChar(gzfile(filename, 'r'), 4)
    if (!identical(magic, 'BAM\1')){
        stop("Input a valid BAM file.")
    }

    ## do awesome stuff with BAM
}
</code></pre>

CC BY-SA 4.0
2018-05-03T17:36:11.747Z
R has a function that specifically performs `any(class(out) == 'error')`: `inherits(out, 'error')`. Besides being more readable this is also potentially more efficient (though it won’t matter here).
Konrad Rudolph
CC BY-SA 4.0
2018-05-03T18:27:22.017Z
@KonradRudolph You're right, I wasn't thinking clear. Edited.
EB2127
CC BY-SA 4.0
2018-05-03T17:13:50.197Z
2018-05-04T09:10:03.657Z
2018-05-04T09:10:03.657Z
EB2127
<p>You won’t know whether it’s a valid BAM file until you attempt reading it in full; even Devon’s method (which I recommend) only does a superficial check — i.e. it checks whether (parts of) the BAM <em>header</em> can be read correctly. However, this doesn’t guarantee that the file isn’t truncated or contains invalid data.</p>
<p>This is of course a more general problem, but it’s perhaps a bit stranger for BAMs (and other biological formats), as it’s relatively frequent to end up with technically invalid files that were produced by existing software. The only recourse is actually trying to use the file, and to handle errors appropriately.</p>
<p>For a <em>very quick check</em>™ you could also pass the file through <code>gunzip</code> and test whether the “magic bytes” at the beginning of the file equal <code>'BAM\1'</code>:</p>
<pre><code>bgzf_stream = gzfile(filename, 'r')
on.exit(close(bgzf_stream))
magic = readChar(bgzf_stream, 4)
stopifnot(identical(magic, 'BAM\1'))
</code></pre>

CC BY-SA 4.0
2018-05-02T08:38:10.800Z
2021-12-17T12:17:09.147Z
2021-12-17T12:17:09.147Z
Konrad Rudolph
<p>I'm writing a function in R for an R package which takes as input a BAM. </p>

<pre><code>my_func = function(my_bam){
    if (!file.exists(my_bam)){
        stop("Input a valid BAM file.")
    }

    ## do awesome stuff with BAM

}
</code></pre>

<p>Trying to write robust software, I would like to do more of a check whether this BAM is actually a BAM. Above, I'm just using <code>file.exists()</code>. </p>

<p>I could also do something simple like "check whether the file has the extension <code>*.bam</code>" with </p>

<pre><code>grepl('*.bam', my_bam)  ## TRUE for file.bam, FALSE for file.txt
</code></pre>

<p>However, is there a quick way to check that the input <em>is</em> actually a BAM? I would prefer to throw an error here, if the user inputs a *txt or *bedpe. </p>

<p>I don't think it's necessary to <em>validate</em> the BAM per se, whereby I believe most users rely upon Picard:</p>

<p><a href="https://broadinstitute.github.io/picard/command-line-overview.html#ValidateSamFile" rel="noreferrer">https://broadinstitute.github.io/picard/command-line-overview.html#ValidateSamFile</a></p>

<p>My first thought was Rsamtools for this operation:</p>

<p><a href="https://bioconductor.org/packages/release/bioc/html/Rsamtools.html" rel="noreferrer">https://bioconductor.org/packages/release/bioc/html/Rsamtools.html</a></p>

<p>However, it doesn't appear that there is a function here which checks the user inputs a BAM, e.g. <code>BamFile()</code> doesn't appear to throw an error</p>

<pre><code>&gt; library(Rsamtools)
&gt; fake_bam = 'nonsense_string.bam'   ## a string I made up, not a real BAM
&gt; BamFile(fake_bam)
class: BamFile 
path: nonsense_string.bam
index: NA
isOpen: FALSE 
yieldSize: NA 
obeyQname: FALSE 
asMates: FALSE 
qnamePrefixEnd: NA 
qnameSuffixStart: NA 
</code></pre>

<p>How could I "check" that the user is inputting a BAM file? Perhaps pipe to samtools (which doesn't feel very stable in terms of software)? </p>

<r><sam><bioconductor><samtools>
Is there an efficient way to check an input BAM in R?
# Is there an efficient way to check an input BAM in R?

(Asked by: username_0 on 2018-05-01)

I'm writing a function in R for an R package which takes as input a BAM. 
my_func = function(my_bam){
    if (!file.exists(my_bam)){
        stop("Input a valid BAM file.")
    }

    ## do awesome stuff with BAM

}

Trying to write robust software, I would like to do more of a check whether this BAM is actually a BAM. Above, I'm just using file.exists(). 
I could also do something simple like "check whether the file has the extension *.bam" with 
grepl('*.bam', my_bam)  ## TRUE for file.bam, FALSE for file.txt

However, is there a quick way to check that the input is actually a BAM? I would prefer to throw an error here, if the user inputs a *txt or *bedpe. 
I don't think it's necessary to validate the BAM per se, whereby I believe most users rely upon Picard:
https://broadinstitute.github.io/picard/command-line-overview.html#ValidateSamFile
My first thought was Rsamtools for this operation:
https://bioconductor.org/packages/release/bioc/html/Rsamtools.html
However, it doesn't appear that there is a function here which checks the user inputs a BAM, e.g. BamFile() doesn't appear to throw an error
> library(Rsamtools)
> fake_bam = 'nonsense_string.bam'   ## a string I made up, not a real BAM
> BamFile(fake_bam)
class: BamFile 
path: nonsense_string.bam
index: NA
isOpen: FALSE 
yieldSize: NA 
obeyQname: FALSE 
asMates: FALSE 
qnamePrefixEnd: NA 
qnameSuffixStart: NA 

How could I "check" that the user is inputting a BAM file? Perhaps pipe to samtools (which doesn't feel very stable in terms of software)?

**Tags:** r, sam, bioconductor, samtools

---

## 3 answers

### Answer by username_2 on 2018-05-02. Score: 6 | Accepted answer

You won’t know whether it’s a valid BAM file until you attempt reading it in full; even Devon’s method (which I recommend) only does a superficial check — i.e. it checks whether (parts of) the BAM header can be read correctly. However, this doesn’t guarantee that the file isn’t truncated or contains invalid data.
This is of course a more general problem, but it’s perhaps a bit stranger for BAMs (and other biological formats), as it’s relatively frequent to end up with technically invalid files that were produced by existing software. The only recourse is actually trying to use the file, and to handle errors appropriately.
For a very quick check™ you could also pass the file through gunzip and test whether the “magic bytes” at the beginning of the file equal 'BAM\1':
bgzf_stream = gzfile(filename, 'r')
on.exit(close(bgzf_stream))
magic = readChar(bgzf_stream, 4)
stopifnot(identical(magic, 'BAM\1'))


---

### Answer by username_1 on 2018-05-02. Score: 3

Take your BamFile(fake_bam) and pass it through open(). That will return a value if fake_bam is a real BAM (or CRAM or maybe SAM) file and through an error otherwise. You can then wrap all of that in a trycatch():
trycatch(open(BamFile(fake_bam)), do something, do something else)

Alternatively, ditch the trycatch() and let open() return the error if an invalid file in entered.


---

### Answer by username_0 on 2018-05-03. Score: 1

Just expanding upon the answers by @DevonRyan and @KonradRudolph, here's one way to put this in an R package:
Either using open(BamFile() from Devon's answer, which needs Rsamtools:
my_func = function(my_bam){

    out = tryCatch(open(Rsamtools::BamFile(my_bam)), error = function(e) e)
    if (inherits(out, "error")){
        stop("Input a valid BAM file.")
    }

    ## do awesome stuff with BAM
}

Or from Konrad's answer
my_func = function(my_bam){

    magic = readChar(gzfile(filename, 'r'), 4)
    if (!identical(magic, 'BAM\1')){
        stop("Input a valid BAM file.")
    }

    ## do awesome stuff with BAM
}

> **Comments:**
> **username_2**: R has a function that specifically performs `any(class(out) == 'error')`: `inherits(out, 'error')`. Besides being more readable this is also potentially more efficient (though it won’t matter here).  
> **username_0**: @KonradRudolph You're right, I wasn't thinking clear. Edited.  

---

