This is what
expand is for, e.g.
expand -t 4 file.txt.
expand won't edit the original file, but you can redirect to a new file and
mv it over the original, or use
sponge if you have it installed, e.g.
expand -t 4 file.txt > file.new && mv file.new file.txt
expand -t 4 file.txt | sponge file.txt
unexpand to do the reverse, convert multiple spaces to tabs.
unexpand support using fixed-width tabs (e.g.
-t 4 or
-t 8, etc) or a list of tab positions (e.g.
-t 4,12,32). They also have options to only convert initial, leading spaces/tabs. See the man pages for details.
For more info about
man sponge and Is there a standard alternative to sponge to pipe a file into itself?. In short, it does the redirect and mv for you, using a temporary file. BTW, never try to redirect stdout to the same file that's currently being used as stdin. The shell will overwrite it before it even gets read.
sponge is from the moreutils package.
PS: See also GNU indent or one of many other similar source-code reformatting tools.